summaryrefslogtreecommitdiff
path: root/JPratt/src/main/java/bjc/pratt/PrattParser.java
diff options
context:
space:
mode:
authorStudent <student@Administrators-iMac-2.local>2017-04-12 11:05:57 -0400
committerStudent <student@Administrators-iMac-2.local>2017-04-12 11:05:57 -0400
commit22c356cd411cf0fcc18d548291af26bc7588a3aa (patch)
tree4f24fdda182b358ca96aed2249bb4e8a19994747 /JPratt/src/main/java/bjc/pratt/PrattParser.java
parent2dc1b5dd145ab0e2b3e3df67f967a9c07ed6d303 (diff)
parentf394306a4b65a3328551f9f6b8d4abff8bfd5b27 (diff)
Merge branch 'master' of https://github.com/bculkin2442/JPratt.git
Diffstat (limited to 'JPratt/src/main/java/bjc/pratt/PrattParser.java')
-rw-r--r--JPratt/src/main/java/bjc/pratt/PrattParser.java204
1 files changed, 140 insertions, 64 deletions
diff --git a/JPratt/src/main/java/bjc/pratt/PrattParser.java b/JPratt/src/main/java/bjc/pratt/PrattParser.java
index e08a67c..7783736 100644
--- a/JPratt/src/main/java/bjc/pratt/PrattParser.java
+++ b/JPratt/src/main/java/bjc/pratt/PrattParser.java
@@ -1,28 +1,34 @@
package bjc.pratt;
-import bjc.pratt.commands.DefaultInitialCommand;
-import bjc.pratt.commands.DefaultNonInitialCommand;
+import java.util.HashMap;
+import java.util.Map;
+
+import bjc.pratt.commands.InitialCommand;
+import bjc.pratt.commands.MetaInitialCommand;
+import bjc.pratt.commands.MetaNonInitialCommand;
+import bjc.pratt.commands.NonInitialCommand;
+import bjc.pratt.commands.impls.DefaultInitialCommand;
+import bjc.pratt.commands.impls.DefaultNonInitialCommand;
+import bjc.pratt.tokens.Token;
+import bjc.pratt.tokens.TokenStream;
import bjc.utils.data.ITree;
import bjc.utils.funcutils.NumberUtils;
import bjc.utils.parserutils.ParserException;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* A configurable Pratt parser for expressions.
- *
+ *
* @author EVE
- *
+ *
* @param <K>
* The key type for the tokens.
- *
+ *
* @param <V>
* The value type for the tokens.
- *
+ *
* @param <C>
* The state type of the parser.
- *
+ *
*
*/
public class PrattParser<K, V, C> {
@@ -35,94 +41,97 @@ public class PrattParser<K, V, C> {
/*
* Left-commands that depend on what the null command was.
*/
- private Map<K, Map<K, NonInitialCommand<K, V, C>>> dependantLeftCommands;
-
+ private final Map<K, Map<K, NonInitialCommand<K, V, C>>> dependantLeftCommands;
+ private final Map<K, Map<K, MetaNonInitialCommand<K, V, C>>> dependantMetaLeftCommands;
/*
* The left commands.
*/
- private Map<K, NonInitialCommand<K, V, C>> leftCommands;
+ private final Map<K, NonInitialCommand<K, V, C>> leftCommands;
+ private final Map<K, MetaNonInitialCommand<K, V, C>> metaLeftCommands;
+
/*
* The initial commands.
*/
- private Map<K, InitialCommand<K, V, C>> nullCommands;
+ private final Map<K, InitialCommand<K, V, C>> nullCommands;
+ private final Map<K, MetaInitialCommand<K, V, C>> metaNullCommands;
+
/*
* Initial commands only checked for statements.
*/
- private Map<K, InitialCommand<K, V, C>> statementCommands;
+ private final Map<K, InitialCommand<K, V, C>> statementCommands;
+ private final Map<K, MetaInitialCommand<K, V, C>> metaStatementCommands;
/**
* Create a new Pratt parser.
- *
+ *
*/
public PrattParser() {
dependantLeftCommands = new HashMap<>();
+ dependantMetaLeftCommands = new HashMap<>();
leftCommands = new HashMap<>();
+ metaLeftCommands = new HashMap<>();
+
nullCommands = new HashMap<>();
+ metaNullCommands = new HashMap<>();
+
statementCommands = new HashMap<>();
+ metaStatementCommands = new HashMap<>();
}
/**
* Parse an expression.
- *
+ *
* @param precedence
* The initial precedence for the expression.
- *
+ *
* @param tokens
* The tokens for the expression.
- *
+ *
* @param state
* The state of the parser.
- *
+ *
* @param isStatement
* Whether or not to parse statements.
- *
+ *
* @return The expression as an AST.
- *
+ *
* @throws ParserException
* If something goes wrong during parsing.
*/
- public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state,
- boolean isStatement) throws ParserException {
- if (precedence < 0) {
+ public ITree<Token<K, V>> parseExpression(final int precedence, final TokenStream<K, V> tokens, final C state,
+ final boolean isStatement) throws ParserException {
+ if (precedence < 0)
throw new IllegalArgumentException("Precedence must be greater than zero");
- }
- Token<K, V> initToken = tokens.current();
+ ParserContext<K, V, C> parserContext = new ParserContext<>(tokens, this, state);
+
+ final Token<K, V> initToken = tokens.current();
tokens.next();
- K initKey = initToken.getKey();
+ final K initKey = initToken.getKey();
- ITree<Token<K, V>> ast;
+ InitialCommand<K, V, C> nullCommand = getInitialCommand(isStatement, initKey, parserContext);
+ ITree<Token<K, V>> ast = nullCommand.denote(initToken, parserContext);
- if (isStatement && statementCommands.containsKey(initKey)) {
- ast = statementCommands.getOrDefault(initKey, DEFAULT_NULL_COMMAND).denote(initToken,
- new ParserContext<>(tokens, this, state));
- } else {
- ast = nullCommands.getOrDefault(initKey, DEFAULT_NULL_COMMAND).denote(initToken,
- new ParserContext<>(tokens, this, state));
- }
+ parserContext.initial = initKey;
int rightPrec = Integer.MAX_VALUE;
while (true) {
- Token<K, V> tok = tokens.current();
+ final Token<K, V> tok = tokens.current();
- K key = tok.getKey();
+ final 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);
- }
+ NonInitialCommand<K, V, C> leftCommand = getNonInitialCommand(key, parserContext);
- int leftBind = command.leftBinding();
+ final int leftBind = leftCommand.leftBinding();
if (NumberUtils.between(precedence, rightPrec, leftBind)) {
tokens.next();
- ast = command.denote(ast, tok, new ParserContext<>(tokens, this, state));
- rightPrec = command.nextBinding();
+ ast = leftCommand.denote(ast, tok, parserContext);
+ rightPrec = leftCommand.nextBinding();
} else {
break;
}
@@ -133,58 +142,125 @@ public class PrattParser<K, V, C> {
/**
* Add a non-initial command to this parser.
- *
+ *
* @param marker
* The key that marks the command.
- *
+ *
* @param comm
* The command.
*/
- public void addNonInitialCommand(K marker, NonInitialCommand<K, V, C> comm) {
+ public void addNonInitialCommand(final K marker, final NonInitialCommand<K, V, C> comm) {
leftCommands.put(marker, comm);
}
/**
* Add a initial command to this parser.
- *
+ *
* @param marker
* The key that marks the command.
- *
+ *
* @param comm
* The command.
*/
- public void addInitialCommand(K marker, InitialCommand<K, V, C> comm) {
+ public void addInitialCommand(final K marker, final InitialCommand<K, V, C> comm) {
nullCommands.put(marker, comm);
}
/**
* Add a statement command to this parser.
- *
+ *
* The difference between statements and initial commands is that
* statements can only appear at the start of the expression.
- *
+ *
* @param marker
* The key that marks the command.
- *
+ *
* @param comm
* The command.
*/
- public void addStatementCommand(K marker, InitialCommand<K, V, C> comm) {
+ public void addStatementCommand(final K marker, final InitialCommand<K, V, C> comm) {
statementCommands.put(marker, comm);
}
/**
- * Add a dependant non-initial command to this parser.
+ * Add a dependent non-initial command to this parser.
+ *
+ * @param dependant
+ * The dependent that precedes the command.
+ *
+ * @param marker
+ * The token key that marks the command.
+ *
+ * @param comm
+ * The command.
*/
- 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<>();
+ public void addDependantCommand(final K dependant, final K marker, final NonInitialCommand<K, V, C> comm) {
+ Map<K, NonInitialCommand<K, V, C>> dependantMap = dependantLeftCommands.getOrDefault(dependant,
+ new HashMap<>());
- comms.put(marker, comm);
+ dependantMap.put(marker, comm);
+ }
- dependantLeftCommands.put(dependant, comms);
+ /**
+ * Lookup an initial command.
+ *
+ * @param isStatement
+ * Whether to look for statement commands or not.
+ *
+ * @param key
+ * The key of the command.
+ *
+ * @param ctx
+ * The context for meta-commands.
+ *
+ * @return A command attached to that key, or a default implementation.
+ */
+ public InitialCommand<K, V, C> getInitialCommand(boolean isStatement, K key, ParserContext<K, V, C> ctx) {
+ if (isStatement) {
+ if (metaStatementCommands.containsKey(key))
+ return metaStatementCommands.get(key).getCommand(ctx);
+ else if (statementCommands.containsKey(key))
+ return statementCommands.get(key);
}
+
+ if (metaNullCommands.containsKey(key))
+ return metaNullCommands.get(key).getCommand(ctx);
+ else
+ return nullCommands.getOrDefault(key, DEFAULT_NULL_COMMAND);
+ }
+
+ /**
+ * Lookup a non-initial command.
+ *
+ * @param key
+ * The key of the command.
+ *
+ * @param ctx
+ * The context for meta-commands.
+ *
+ * @return A command attached to that key, or a default implementation.
+ */
+ public NonInitialCommand<K, V, C> getNonInitialCommand(K key, ParserContext<K, V, C> ctx) {
+ if (dependantMetaLeftCommands.containsKey(ctx.initial)) {
+ Map<K, MetaNonInitialCommand<K, V, C>> dependantCommands = dependantMetaLeftCommands
+ .get(ctx.initial);
+
+ if (dependantCommands.containsKey(key)) {
+ return dependantCommands.get(key).getCommand(ctx);
+ }
+ }
+
+ if (dependantLeftCommands.containsKey(ctx.initial)) {
+ Map<K, NonInitialCommand<K, V, C>> dependantCommands = dependantLeftCommands.get(ctx.initial);
+
+ if (dependantCommands.containsKey(key)) {
+ return dependantCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND);
+ }
+ }
+
+ if (metaLeftCommands.containsKey(key)) {
+ return metaLeftCommands.get(key).getCommand(ctx);
+ } else
+ return leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND);
}
} \ No newline at end of file