From 42990231fee502552b769b9af4c04ac0dcaeb195 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sat, 25 Mar 2017 19:13:42 -0400 Subject: Update Pratt parser --- .../bjc/utils/examples/parsing/AssignCommand.java | 2 +- .../utils/examples/parsing/PrattParserTest.java | 4 +- .../bjc/utils/examples/parsing/SwitchCommand.java | 2 +- .../bjc/utils/examples/parsing/VarCommand.java | 2 +- .../bjc/utils/parserutils/pratt/ParseBlock.java | 37 ++++++++ .../bjc/utils/parserutils/pratt/StringToken.java | 78 ---------------- .../utils/parserutils/pratt/StringTokenStream.java | 44 --------- .../bjc/utils/parserutils/pratt/TokenStream.java | 23 ++--- .../parserutils/pratt/blocks/ParseBlocks.java | 13 +++ .../pratt/blocks/RepeatingParseBlock.java | 96 ++++++++++++++++++++ .../parserutils/pratt/blocks/SimpleParseBlock.java | 101 +++++++++++++++++++++ .../pratt/blocks/TriggeredParseBlock.java | 61 +++++++++++++ .../pratt/commands/BinaryPostCommand.java | 29 +++++- .../pratt/commands/DelimitedCommand.java | 65 ------------- .../pratt/commands/GroupingCommand.java | 41 +++++++-- .../pratt/commands/InitialCommands.java | 26 +++++- .../parserutils/pratt/commands/LeafCommand.java | 18 +++- .../pratt/commands/LeftBinaryCommand.java | 24 ++++- .../pratt/commands/NonBinaryCommand.java | 24 ++++- .../pratt/commands/NonInitialCommands.java | 10 +- .../pratt/commands/PostCircumfixCommand.java | 54 ++++++++--- .../parserutils/pratt/commands/PostfixCommand.java | 28 +++++- .../pratt/commands/PreTernaryCommand.java | 72 ++++++++++----- .../pratt/commands/RightBinaryCommand.java | 22 ++++- .../parserutils/pratt/commands/TernaryCommand.java | 54 ++++++++--- .../pratt/commands/TransformingInitialCommand.java | 52 +++++++++++ .../parserutils/pratt/commands/UnaryCommand.java | 28 +++++- .../parserutils/pratt/tokens/StringToken.java | 80 ++++++++++++++++ .../pratt/tokens/StringTokenStream.java | 54 +++++++++++ 29 files changed, 861 insertions(+), 283 deletions(-) create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/ParseBlock.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringToken.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringTokenStream.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/RepeatingParseBlock.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/SimpleParseBlock.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/TriggeredParseBlock.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TransformingInitialCommand.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/AssignCommand.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/AssignCommand.java index 9cd30a8..d743c21 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/AssignCommand.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/AssignCommand.java @@ -4,9 +4,9 @@ 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.StringToken; import bjc.utils.parserutils.pratt.Token; import bjc.utils.parserutils.pratt.commands.NonBinaryCommand; +import bjc.utils.parserutils.pratt.tokens.StringToken; class AssignCommand extends NonBinaryCommand { public AssignCommand() { 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 110d331..6b97c19 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 @@ -5,9 +5,9 @@ import bjc.utils.data.TransformIterator; import bjc.utils.esodata.Directory; import bjc.utils.parserutils.ParserException; import bjc.utils.parserutils.pratt.PrattParser; -import bjc.utils.parserutils.pratt.StringToken; -import bjc.utils.parserutils.pratt.StringTokenStream; import bjc.utils.parserutils.pratt.Token; +import bjc.utils.parserutils.pratt.tokens.StringToken; +import bjc.utils.parserutils.pratt.tokens.StringTokenStream; import bjc.utils.parserutils.splitter.TokenSplitter; import bjc.utils.parserutils.splitter.TwoLevelSplitter; diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/SwitchCommand.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/SwitchCommand.java index 7464709..78d8093 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/SwitchCommand.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/SwitchCommand.java @@ -5,8 +5,8 @@ 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.StringToken; import bjc.utils.parserutils.pratt.Token; +import bjc.utils.parserutils.pratt.tokens.StringToken; class SwitchCommand implements InitialCommand { @Override diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/VarCommand.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/VarCommand.java index b702f0e..5cf4b25 100644 --- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/VarCommand.java +++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/VarCommand.java @@ -4,9 +4,9 @@ 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.StringToken; import bjc.utils.parserutils.pratt.Token; import bjc.utils.parserutils.pratt.commands.AbstractInitialCommand; +import bjc.utils.parserutils.pratt.tokens.StringToken; class VarCommand extends AbstractInitialCommand { diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/ParseBlock.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/ParseBlock.java new file mode 100644 index 0000000..4542107 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/ParseBlock.java @@ -0,0 +1,37 @@ +package bjc.utils.parserutils.pratt; + +import bjc.utils.data.ITree; +import bjc.utils.parserutils.ParserException; + +/** + * Represents a embedded block in an expression. + * + * @author bjculkin + * + * @param + * The key type of the token. + * + * @param + * The value type of the token. + * + * @param + * The state type of the parser. + */ +@FunctionalInterface +public interface ParseBlock { + + /** + * Parse the block this represents. + * + * @param ctx + * The context for parsing. + * + * @return A AST for this block. + * + * @throws ParserException + * If something goes wrong during parsing, or the block + * fails validation. + */ + ITree> parse(ParserContext ctx) throws ParserException; + +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringToken.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringToken.java deleted file mode 100644 index 74f9c63..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringToken.java +++ /dev/null @@ -1,78 +0,0 @@ -package bjc.utils.parserutils.pratt; - -/** - * Simple token implementation for strings. - * - * @author EVE - * - */ -public class StringToken implements Token { - private String key; - private String val; - - /** - * Create a new string token. - * - * @param ky - * The key for the token. - * - * @param vl - * The value for the token. - */ - public StringToken(String ky, String vl) { - key = ky; - val = vl; - } - - @Override - public String getKey() { - return key; - } - - @Override - public String getValue() { - return val; - } - - @Override - public int hashCode() { - final int prime = 31; - - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - result = prime * result + ((val == null) ? 0 : val.hashCode()); - - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof StringToken)) - return false; - - StringToken other = (StringToken) obj; - - if (key == null) { - if (other.key != null) - return false; - } else if (!key.equals(other.key)) - return false; - - if (val == null) { - if (other.val != null) - return false; - } else if (!val.equals(other.val)) - return false; - - return true; - } - - @Override - public String toString() { - return String.format("StringToken [key='%s', val='%s']", key, val); - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringTokenStream.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringTokenStream.java deleted file mode 100644 index 8caeef9..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/StringTokenStream.java +++ /dev/null @@ -1,44 +0,0 @@ -package bjc.utils.parserutils.pratt; - -import java.util.Iterator; - -/** - * Simple implementation of token stream for strings. - * - * The terminal token here is represented by a token with type '(end)' and null - * value. - * - * @author EVE - * - */ -public class StringTokenStream implements TokenStream { - private Iterator> iter; - - private Token curr; - - /** - * Create a new token stream from a iterator. - * - * @param itr - * The iterator to use. - * - */ - public StringTokenStream(Iterator> itr) { - iter = itr; - - } - - @Override - public Token current() { - return curr; - } - - @Override - public void next() { - if(iter.hasNext()) { - curr = iter.next(); - } else { - curr = new StringToken("(end)", null); - } - } -} 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 8decc09..71482b4 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 @@ -4,6 +4,7 @@ import bjc.utils.funcutils.StringUtils; import bjc.utils.parserutils.ParserException; import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; /** @@ -17,7 +18,7 @@ import java.util.Set; * @param * The value type of the token. */ -public interface TokenStream { +public abstract class TokenStream implements Iterator> { /** * The exception thrown when an expectation fails. * @@ -41,14 +42,13 @@ public interface TokenStream { * * @return The current token. */ - Token current(); + public abstract Token current(); - /** - * Advance to the next token in the stream. - * - * Has no effect when the end of the stream is reached. - */ - void next(); + @Override + public abstract Token next(); + + @Override + public abstract boolean hasNext(); /** * Utility method for checking that the next token is one of a specific @@ -60,10 +60,10 @@ public interface TokenStream { * @throws ExpectationException * If the token is not one of the expected types. */ - default void expect(Set expectedKeys) throws ExpectationException { + public void expect(Set expectedKeys) throws ExpectationException { K curKey = current().getKey(); - if(!expectedKeys.contains(curKey)) { + if (!expectedKeys.contains(curKey)) { String expectedList = StringUtils.toEnglishList(expectedKeys.toArray(), false); throw new ExpectationException("One of '" + expectedList + "' was expected, not " + curKey); @@ -82,7 +82,8 @@ public interface TokenStream { * @throws ExpectationException * If the token is not one of the expected types. */ - default void expect(@SuppressWarnings("unchecked") K... expectedKeys) throws ExpectationException { + @SafeVarargs + public final void expect(K... expectedKeys) throws ExpectationException { expect(new HashSet<>(Arrays.asList(expectedKeys))); } } 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 new file mode 100644 index 0000000..43163e6 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java @@ -0,0 +1,13 @@ +package bjc.utils.parserutils.pratt.blocks; + +import bjc.utils.parserutils.pratt.ParseBlock; + +/** + * Utility class for creating common implementations of {@link ParseBlock} + * + * @author bjculkin + * + */ +public class ParseBlocks { + +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/RepeatingParseBlock.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/RepeatingParseBlock.java new file mode 100644 index 0000000..08a4bae --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/RepeatingParseBlock.java @@ -0,0 +1,96 @@ +package bjc.utils.parserutils.pratt.blocks; + +import java.util.function.UnaryOperator; + +import bjc.utils.data.ITree; +import bjc.utils.data.Tree; +import bjc.utils.parserutils.ParserException; +import bjc.utils.parserutils.pratt.ParseBlock; +import bjc.utils.parserutils.pratt.ParserContext; +import bjc.utils.parserutils.pratt.Token; + +/** + * A parse block that can parse a sequnce of zero or more occurances of another + * block. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ +public class RepeatingParseBlock implements ParseBlock { + private ParseBlock innerBlock; + + private K delim; + private K term; + + private UnaryOperator onDelim; + + private Token mark; + + /** + * Create a new repeating block. + * + * @param inner + * The inner block for elements. + * + * @param delimiter + * The token that delimits elements in the sequence. + * + * @param terminator + * The token that terminates the sequence. + * + * @param marker + * The token to use as the node in the AST. + * + * @param action + * The action to apply to the state after every + * delimiter. + */ + public RepeatingParseBlock(ParseBlock inner, K delimiter, K terminator, Token marker, + UnaryOperator action) { + super(); + + if (inner == null) + throw new NullPointerException("Inner block must not be null"); + else if (delimiter == null) + throw new NullPointerException("Delimiter must not be null"); + else if (terminator == null) throw new NullPointerException("Terminator must not be null"); + + innerBlock = inner; + + delim = delimiter; + term = terminator; + + mark = marker; + + onDelim = action; + } + + @Override + public ITree> parse(ParserContext ctx) throws ParserException { + ITree> ret = new Tree<>(mark); + + Token tok = ctx.tokens.current(); + + while (!tok.getKey().equals(term)) { + ITree> kid = innerBlock.parse(ctx); + ret.addChild(kid); + + tok = ctx.tokens.current(); + + ctx.tokens.expect(delim, term); + + if (onDelim != null) ctx.state = onDelim.apply(ctx.state); + } + + return ret; + } + +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/SimpleParseBlock.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/SimpleParseBlock.java new file mode 100644 index 0000000..c2e9e54 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/SimpleParseBlock.java @@ -0,0 +1,101 @@ +package bjc.utils.parserutils.pratt.blocks; + +import java.util.function.Predicate; + +import bjc.utils.data.ITree; +import bjc.utils.parserutils.ParserException; +import bjc.utils.parserutils.pratt.ParseBlock; +import bjc.utils.parserutils.pratt.ParserContext; +import bjc.utils.parserutils.pratt.Token; + +/** + * Simple implementation of {@link ParseBlock} + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ +public class SimpleParseBlock implements ParseBlock { + private int pow; + + private K term; + + private Predicate>> validatr; + + /** + * Create a new block. + * + * @param precedence + * The precedence of this block. + * + * @param terminator + * The token type that terminates the block. If this is + * null, don't check for a terminator. + * + * @param validator + * The predicate to apply to blocks. + */ + public SimpleParseBlock(int precedence, K terminator, Predicate>> validator) { + if (precedence < 0) throw new IllegalArgumentException("Precedence must be non-negative"); + + pow = precedence; + term = terminator; + validatr = validator; + } + + @Override + public ITree> parse(ParserContext ctx) throws ParserException { + ITree> res = ctx.parse.parseExpression(pow, ctx.tokens, ctx.state, false); + + if (term != null) { + ctx.tokens.expect(term); + } + + if (validatr == null || validatr.test(res)) { + return res; + } + + throw new ParserException("Block failed validation"); + } + + @Override + public int hashCode() { + final int prime = 31; + + int result = 1; + + result = prime * result + pow; + result = prime * result + ((term == null) ? 0 : term.hashCode()); + + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof SimpleParseBlock)) return false; + + SimpleParseBlock other = (SimpleParseBlock) obj; + + if (pow != other.pow) return false; + + if (term == null) { + if (other.term != null) return false; + } else if (!term.equals(other.term)) return false; + + return true; + } + + @Override + public String toString() { + return String.format("ParseBlock [pow=%s, term='%s']", pow, term); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/TriggeredParseBlock.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/TriggeredParseBlock.java new file mode 100644 index 0000000..fbfc61b --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/TriggeredParseBlock.java @@ -0,0 +1,61 @@ +package bjc.utils.parserutils.pratt.blocks; + +import java.util.function.UnaryOperator; + +import bjc.utils.data.ITree; +import bjc.utils.parserutils.ParserException; +import bjc.utils.parserutils.pratt.ParseBlock; +import bjc.utils.parserutils.pratt.ParserContext; +import bjc.utils.parserutils.pratt.Token; + +/** + * A parse block that can adjust the state before handling its context. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * @param + * The value type of the tokens. + * @param + * The state type of the parser. + */ +public class TriggeredParseBlock implements ParseBlock { + private UnaryOperator onEnter; + private UnaryOperator onExit; + + private ParseBlock source; + + /** + * Create a new triggered parse block. + * + * @param onEnter + * The action to fire before parsing the block. + * + * @param onExit + * The action to fire after parsing the block. + * + * @param source + * The block to use for parsing. + */ + public TriggeredParseBlock(UnaryOperator onEnter, UnaryOperator onExit, ParseBlock source) { + super(); + this.onEnter = onEnter; + this.onExit = onExit; + this.source = source; + } + + @Override + public ITree> parse(ParserContext ctx) throws ParserException { + C newState = onEnter.apply(ctx.state); + + ParserContext newCtx = new ParserContext<>(ctx.tokens, ctx.parse, newState); + + ITree> res = source.parse(newCtx); + + ctx.state = onExit.apply(newState); + + return res; + } + +} 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 index 7aaf735..806f2f3 100644 --- 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 @@ -2,14 +2,35 @@ package bjc.utils.parserutils.pratt.commands; import bjc.utils.parserutils.pratt.NonInitialCommand; -/* - * A command with constant binding power. +/** + * A operator with fixed precedence. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. */ public abstract class BinaryPostCommand extends NonInitialCommand { private final int leftPower; - public BinaryPostCommand(int power) { - leftPower = power; + /** + * 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 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 deleted file mode 100644 index 090b2f4..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java +++ /dev/null @@ -1,65 +0,0 @@ -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 extends AbstractInitialCommand { - private int inner; - - private K delim; - private K mark; - - private Token term; - - private UnaryOperator onEnter; - private UnaryOperator onDelim; - private UnaryOperator onExit; - - private boolean statement; - - public DelimitedCommand(int inner, K delim, K mark, Token term, UnaryOperator onEnter, - UnaryOperator onDelim, UnaryOperator 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> intNullDenotation(Token operator, ParserContext ctx) - throws ParserException { - C newState = onEnter.apply(ctx.state); - - IList>> kids = new FunctionalList<>(); - - while(true) { - ITree> kid = ctx.parse.parseExpression(inner, ctx.tokens, newState, - statement); - kids.add(kid); - - Token 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 index 407a39e..37cc6ee 100644 --- 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 @@ -3,27 +3,48 @@ 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.ParseBlock; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A grouping operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class GroupingCommand extends AbstractInitialCommand { - private K term; - private Token mark; - private int inner; + private ParseBlock innerBlock; + + private Token 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 inner, Token marker) { + innerBlock = inner; - public GroupingCommand(int innerPrec, K terminator, Token marker) { - inner = innerPrec; - term = terminator; mark = marker; } - @SuppressWarnings("unchecked") @Override protected ITree> intNullDenotation(Token operator, ParserContext ctx) throws ParserException { - ITree> opr = ctx.parse.parseExpression(inner, ctx.tokens, ctx.state, false); - - ctx.tokens.expect(term); + ITree> opr = innerBlock.parse(ctx); return new Tree<>(mark, opr); } 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 d9e7f90..bad5964 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 @@ -2,7 +2,11 @@ package bjc.utils.parserutils.pratt.commands; 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; @@ -41,7 +45,9 @@ public class InitialCommands { * @return A command implementing the operator. */ public static InitialCommand grouping(int precedence, K term, Token mark) { - return new GroupingCommand<>(precedence, term, mark); + ParseBlock innerBlock = new SimpleParseBlock<>(precedence, term, null); + + return new GroupingCommand<>(innerBlock, mark); } /** @@ -78,7 +84,11 @@ public class InitialCommands { */ public static InitialCommand preTernary(int cond1, int block1, int block2, K mark1, K mark2, Token term) { - return new PreTernaryCommand<>(cond1, block1, block2, mark1, mark2, term); + ParseBlock condBlock = new SimpleParseBlock<>(cond1, mark1, null); + ParseBlock opblock1 = new SimpleParseBlock<>(block1, mark2, null); + ParseBlock opblock2 = new SimpleParseBlock<>(block2, null, null); + + return new PreTernaryCommand<>(condBlock, opblock1, opblock2, term); } /** @@ -129,6 +139,16 @@ public class InitialCommands { public static InitialCommand delimited(int inner, K delim, K mark, Token term, UnaryOperator onEnter, UnaryOperator onDelim, UnaryOperator onExit, boolean statement) { - return new DelimitedCommand<>(inner, delim, mark, term, onEnter, onDelim, onExit, statement); + ParseBlock innerBlock = new SimpleParseBlock<>(inner, null, null); + ParseBlock delimsBlock = new RepeatingParseBlock<>(innerBlock, delim, mark, term, onDelim); + ParseBlock scopedBlock = new TriggeredParseBlock<>(onEnter, onExit, delimsBlock); + + GroupingCommand command = new GroupingCommand<>(scopedBlock, term); + + /* + * Remove the wrapper layer from grouping-command on top of + * RepeatingParseBlock. + */ + return new TransformingInitialCommand<>(command, (tree) -> tree.getChild(0)); } } 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 index 87fe7c1..3937f5f 100644 --- 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 @@ -7,11 +7,23 @@ import bjc.utils.parserutils.pratt.InitialCommand; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A operator that stands for itself. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class LeafCommand implements InitialCommand { @Override - public ITree> denote(Token operator, ParserContext ctx) - throws ParserException { - + public ITree> denote(Token operator, ParserContext 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 index 1306735..58d7261 100644 --- 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 @@ -1,8 +1,28 @@ package bjc.utils.parserutils.pratt.commands; +/** + * A left-associative operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class LeftBinaryCommand extends BinaryCommand { - public LeftBinaryCommand(int leftPower) { - super(leftPower); + /** + * Create a new left-associative operator. + * + * @param precedence + * The precedence of the operator. + */ + public LeftBinaryCommand(int precedence) { + super(precedence); } @Override 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 index 36ea0e1..d32a1a7 100644 --- 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 @@ -1,8 +1,28 @@ package bjc.utils.parserutils.pratt.commands; +/** + * A non-associative operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class NonBinaryCommand extends BinaryCommand { - public NonBinaryCommand(int leftPower) { - super(leftPower); + /** + * Create a new non-associative operator. + * + * @param precedence + * The precedence of the operator. + */ + public NonBinaryCommand(int precedence) { + super(precedence); } @Override 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 index 086ecf8..45bdc51 100644 --- 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 @@ -1,7 +1,9 @@ package bjc.utils.parserutils.pratt.commands; import bjc.utils.parserutils.pratt.NonInitialCommand; +import bjc.utils.parserutils.pratt.ParseBlock; import bjc.utils.parserutils.pratt.Token; +import bjc.utils.parserutils.pratt.blocks.SimpleParseBlock; import java.util.Set; @@ -101,7 +103,9 @@ public class NonInitialCommands { */ public static NonInitialCommand postCircumfix(int precedence, int insidePrecedence, K closer, Token marker) { - return new PostCircumfixCommand<>(precedence, insidePrecedence, closer, marker); + ParseBlock innerBlock = new SimpleParseBlock<>(insidePrecedence, closer, null); + + return new PostCircumfixCommand<>(precedence, innerBlock, marker); } /** @@ -129,6 +133,8 @@ public class NonInitialCommands { */ public static NonInitialCommand ternary(int precedence, int insidePrecedence, K closer, Token marker, boolean nonassoc) { - return new TernaryCommand<>(insidePrecedence, closer, marker, nonassoc); + ParseBlock innerBlock = new SimpleParseBlock<>(insidePrecedence, closer, null); + + return new TernaryCommand<>(precedence, innerBlock, 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 index ba5099e..90fca00 100644 --- 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 @@ -3,29 +3,57 @@ 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.ParseBlock; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A post-circumfix operator, like array indexing. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class PostCircumfixCommand extends BinaryPostCommand { - private int insidePrec; - private K term; - private Token mark; + private ParseBlock innerBlock; - public PostCircumfixCommand(int leftPower, int insidePower, K terminator, Token marker) { - super(leftPower); + private Token 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 inner, Token marker) { + super(precedence); + + if (inner == null) { + throw new NullPointerException("Inner block must not be null"); + } + + innerBlock = inner; - insidePrec = insidePower; - term = terminator; mark = marker; } - @SuppressWarnings("unchecked") @Override - public ITree> denote(ITree> operand, Token operator, - ParserContext ctx) throws ParserException { - ITree> inside = ctx.parse.parseExpression(insidePrec, ctx.tokens, ctx.state, false); - - ctx.tokens.expect(term); + public ITree> denote(ITree> operand, Token operator, ParserContext ctx) + throws ParserException { + ITree> inside = innerBlock.parse(ctx); return new Tree<>(mark, operand, inside); } 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 index 19c540a..bab3de4 100644 --- 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 @@ -6,14 +6,34 @@ import bjc.utils.parserutils.ParserException; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A postfix operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class PostfixCommand extends BinaryPostCommand { - public PostfixCommand(int leftPower) { - super(leftPower); + /** + * Create a new postfix operator. + * + * @param precedence + * The precedence of the operator. + */ + public PostfixCommand(int precedence) { + super(precedence); } @Override - public ITree> denote(ITree> operand, Token operator, - ParserContext ctx) throws ParserException { + public ITree> denote(ITree> operand, Token operator, ParserContext 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 index 04604be..42d1a6e 100644 --- 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 @@ -3,43 +3,73 @@ 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.ParseBlock; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A prefix ternary operator, like an if/then/else group. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class PreTernaryCommand extends AbstractInitialCommand { - private int cond1; - private int block1; - private int block2; + private Token term; - private K mark1; - private K mark2; + private ParseBlock condBlock; - private Token term; + private ParseBlock opblock1; + private ParseBlock opblock2; - public PreTernaryCommand(int cond1, int block1, int block2, K mark1, K mark2, Token term) { + /** + * 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 cond, ParseBlock op1, ParseBlock op2, + Token term) { super(); - this.cond1 = cond1; - this.block1 = block1; - this.block2 = block2; - this.mark1 = mark1; - this.mark2 = mark2; + + 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; } - @SuppressWarnings("unchecked") @Override protected ITree> intNullDenotation(Token operator, ParserContext ctx) throws ParserException { - ITree> cond = ctx.parse.parseExpression(cond1, ctx.tokens, ctx.state, false); - - ctx.tokens.expect(mark1); - - ITree> fstBlock = ctx.parse.parseExpression(block1, ctx.tokens, ctx.state, false); + ITree> cond = condBlock.parse(ctx); - ctx.tokens.expect(mark2); + ITree> op1 = opblock1.parse(ctx); - ITree> sndBlock = ctx.parse.parseExpression(block2, ctx.tokens, ctx.state, false); + ITree> op2 = opblock2.parse(ctx); - return new Tree<>(term, cond, fstBlock, sndBlock); + return new Tree<>(term, cond, op1, op2); } } \ 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 index 729c33d..5f3d9f2 100644 --- 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 @@ -1,8 +1,26 @@ package bjc.utils.parserutils.pratt.commands; +/** + * A right-associative binary operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * @param + * The value type of the tokens. + * @param + * The state type of the parser. + */ public class RightBinaryCommand extends BinaryCommand { - public RightBinaryCommand(int leftPower) { - super(leftPower); + /** + * Create a new right-associative operator. + * + * @param precedence + * The precedence of the operator. + */ + public RightBinaryCommand(int precedence) { + super(precedence); } @Override 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 index c3204b9..8f04368 100644 --- 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 @@ -3,33 +3,63 @@ 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.ParseBlock; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A ternary command, like C's ?: + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class TernaryCommand extends BinaryPostCommand { - private K term; - - private int innerExp; + private ParseBlock innerBlck; private Token mark; private boolean nonassoc; - public TernaryCommand(int leftPower, K terminator, Token marker, boolean isNonassoc) { - super(leftPower); + /** + * 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 innerBlock, Token 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"); - term = terminator; + innerBlck = innerBlock; mark = marker; nonassoc = isNonassoc; } - @SuppressWarnings("unchecked") @Override - public ITree> denote(ITree> operand, Token operator, - ParserContext ctx) throws ParserException { - ITree> inner = ctx.parse.parseExpression(innerExp, ctx.tokens, ctx.state, false); - - ctx.tokens.expect(term); + public ITree> denote(ITree> operand, Token operator, ParserContext ctx) + throws ParserException { + ITree> inner = innerBlck.parse(ctx); ITree> outer = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false); diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TransformingInitialCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TransformingInitialCommand.java new file mode 100644 index 0000000..88803df --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TransformingInitialCommand.java @@ -0,0 +1,52 @@ +package bjc.utils.parserutils.pratt.commands; + +import java.util.function.UnaryOperator; + +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; + +/** + * An initial command that transforms the result of another command. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ +public class TransformingInitialCommand extends AbstractInitialCommand { + private InitialCommand internal; + + private UnaryOperator>> 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 internal, + UnaryOperator>> transform) { + super(); + this.internal = internal; + this.transform = transform; + } + + @Override + protected ITree> intNullDenotation(Token operator, ParserContext ctx) + throws ParserException { + return transform.apply(internal.denote(operator, ctx)); + } + +} 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 index 9a79d21..c608362 100644 --- 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 @@ -6,11 +6,35 @@ import bjc.utils.parserutils.ParserException; import bjc.utils.parserutils.pratt.ParserContext; import bjc.utils.parserutils.pratt.Token; +/** + * A unary operator. + * + * @author bjculkin + * + * @param + * The key type of the tokens. + * + * @param + * The value type of the tokens. + * + * @param + * The state type of the parser. + */ public class UnaryCommand extends AbstractInitialCommand { private final int nullPwer; - public UnaryCommand(int nullPower) { - nullPwer = nullPower; + /** + * 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 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 new file mode 100644 index 0000000..7e779aa --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java @@ -0,0 +1,80 @@ +package bjc.utils.parserutils.pratt.tokens; + +import bjc.utils.parserutils.pratt.Token; + +/** + * Simple token implementation for strings. + * + * @author EVE + * + */ +public class StringToken implements Token { + private String key; + private String val; + + /** + * Create a new string token. + * + * @param ky + * The key for the token. + * + * @param vl + * The value for the token. + */ + public StringToken(String ky, String vl) { + key = ky; + val = vl; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getValue() { + return val; + } + + @Override + public int hashCode() { + final int prime = 31; + + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((val == null) ? 0 : val.hashCode()); + + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof StringToken)) + return false; + + StringToken other = (StringToken) obj; + + if (key == null) { + if (other.key != null) + return false; + } else if (!key.equals(other.key)) + return false; + + if (val == null) { + if (other.val != null) + return false; + } else if (!val.equals(other.val)) + return false; + + return true; + } + + @Override + public String toString() { + return String.format("StringToken [key='%s', val='%s']", key, 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 new file mode 100644 index 0000000..d7d4a66 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java @@ -0,0 +1,54 @@ +package bjc.utils.parserutils.pratt.tokens; + +import java.util.Iterator; + +import bjc.utils.parserutils.pratt.Token; +import bjc.utils.parserutils.pratt.TokenStream; + +/** + * Simple implementation of token stream for strings. + * + * The terminal token here is represented by a token with type '(end)' and null + * value. + * + * @author EVE + * + */ +public class StringTokenStream extends TokenStream { + private Iterator> iter; + + private Token curr; + + /** + * Create a new token stream from a iterator. + * + * @param itr + * The iterator to use. + * + */ + public StringTokenStream(Iterator> itr) { + iter = itr; + + } + + @Override + public Token current() { + return curr; + } + + @Override + public Token next() { + if (iter.hasNext()) { + curr = iter.next(); + } else { + curr = new StringToken("(end)", null); + } + + return curr; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } +} -- cgit v1.2.3