summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/parserutils/TreeConstructor.java
diff options
context:
space:
mode:
authorBen Culkin <scorpress@gmail.com>2020-11-12 20:05:01 -0500
committerBen Culkin <scorpress@gmail.com>2020-11-12 20:05:01 -0500
commit6dcd129a10af0034b38bfe843d223c4593deee09 (patch)
treee27cf2574a10da36d9a737e1fef48da8e5681da8 /base/src/main/java/bjc/utils/parserutils/TreeConstructor.java
parentc41cfde634d70c3a50adf3979cc5239e5ae52e73 (diff)
Cleanup part 2
Diffstat (limited to 'base/src/main/java/bjc/utils/parserutils/TreeConstructor.java')
-rw-r--r--base/src/main/java/bjc/utils/parserutils/TreeConstructor.java156
1 files changed, 145 insertions, 11 deletions
diff --git a/base/src/main/java/bjc/utils/parserutils/TreeConstructor.java b/base/src/main/java/bjc/utils/parserutils/TreeConstructor.java
index 3c7509b..6780768 100644
--- a/base/src/main/java/bjc/utils/parserutils/TreeConstructor.java
+++ b/base/src/main/java/bjc/utils/parserutils/TreeConstructor.java
@@ -2,15 +2,11 @@ package bjc.utils.parserutils;
import java.util.Deque;
import java.util.LinkedList;
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-import bjc.data.IHolder;
-import bjc.data.IPair;
-import bjc.data.ITree;
-import bjc.data.Identity;
-import bjc.data.Pair;
+import java.util.function.*;
+
+import bjc.data.*;
import bjc.funcdata.IList;
+import bjc.utils.parserutils.TreeConstructor.*;
/**
* Creates a parse tree from a postfix expression.
@@ -103,13 +99,14 @@ public class TreeConstructor {
/*
* Make sure our parameters are valid
*/
- if (tokens == null)
+ if (tokens == null) {
throw new NullPointerException("Tokens must not be null");
- else if (isOperator == null)
+ } else if (isOperator == null) {
throw new NullPointerException("Operator predicate must not be null");
- else if (isSpecialOperator == null)
+ } else if (isSpecialOperator == null) {
throw new NullPointerException(
"Special operator determiner must not be null");
+ }
final ConstructorState<TokenType> cstate
= new ConstructorState<>(new LinkedList<>(), null);
@@ -127,3 +124,140 @@ public class TreeConstructor {
return initialState.unwrap(ConstructorState::getRight);
}
}
+
+/*
+ * Transform function on tokens
+ */
+class TokenTransformer<TokenType> implements Consumer<TokenType> {
+ /*
+ * Handle operators
+ */
+ private final class OperatorHandler
+ implements UnaryOperator<ConstructorState<TokenType>> {
+ /* The handled element. */
+ private final TokenType element;
+
+ /* Create a new operator handler. */
+ public OperatorHandler(final TokenType element) {
+ this.element = element;
+ }
+
+ @Override
+ public ConstructorState<TokenType> apply(final ConstructorState<TokenType> pair) {
+ /*
+ * Replace the current AST with the result of handling an operator
+ */
+ return new ConstructorState<>(
+ pair.bindLeft(queuedASTs -> handleOperator(queuedASTs)));
+ }
+
+ private ConstructorState<TokenType>
+ handleOperator(final Deque<ITree<TokenType>> queuedASTs) {
+ /*
+ * The AST we're going to hand back
+ */
+ ITree<TokenType> newAST;
+
+ /*
+ * Handle special operators
+ */
+ if (isSpecialOperator.test(element)) {
+ newAST = handleSpecialOperator.apply(element).apply(queuedASTs);
+ } else {
+ /*
+ * Error if we don't have enough for a binary operator
+ */
+ if (queuedASTs.size() < 2) {
+ final String msg = String.format(
+ "Attempted to parse binary operator without enough operands\n\tProblem operator is: %s\n\tPossible operand is: %s",
+ element.toString(), queuedASTs.peek().toString());
+
+ throw new IllegalStateException(msg);
+ }
+
+ /*
+ * Grab the two operands
+ */
+ final ITree<TokenType> right = queuedASTs.pop();
+ final ITree<TokenType> left = queuedASTs.pop();
+
+ /*
+ * Create a new AST
+ */
+ newAST = new Tree<>(element, left, right);
+ }
+
+ /*
+ * Stick it onto the stack
+ */
+ queuedASTs.push(newAST);
+
+ /*
+ * Hand back the state
+ */
+ return new ConstructorState<>(queuedASTs, newAST);
+ }
+ }
+
+ /* The initial state of the transformer. */
+ private final IHolder<ConstructorState<TokenType>> initialState;
+
+ /* The predicate tot use to detect operators. */
+ private final Predicate<TokenType> operatorPredicate;
+
+ /* The predicate for detecting special operators. */
+ private final Predicate<TokenType> isSpecialOperator;
+ /* The function for handling special operators. */
+ private final Function<TokenType, QueueFlattener<TokenType>> handleSpecialOperator;
+
+ /**
+ * Create a new transformer
+ *
+ * @param initialState
+ * The initial state of the transformer.
+ *
+ * @param operatorPredicate
+ * The predicate to use to identify operators.
+ *
+ * @param isSpecialOperator
+ * The predicate used to identify special
+ * operators.
+ *
+ * @param handleSpecialOperator
+ * The function used for handling special
+ * operators.
+ */
+ public TokenTransformer(final IHolder<ConstructorState<TokenType>> initialState,
+ final Predicate<TokenType> operatorPredicate,
+ final Predicate<TokenType> isSpecialOperator,
+ final Function<TokenType, QueueFlattener<TokenType>> handleSpecialOperator) {
+ this.initialState = initialState;
+ this.operatorPredicate = operatorPredicate;
+ this.isSpecialOperator = isSpecialOperator;
+ this.handleSpecialOperator = handleSpecialOperator;
+ }
+
+ @Override
+ public void accept(final TokenType element) {
+ /*
+ * Handle operators
+ */
+ if (operatorPredicate.test(element)) {
+ initialState.transform(new OperatorHandler(element));
+ } else {
+ final ITree<TokenType> newAST = new Tree<>(element);
+
+ /*
+ * Insert the new tree into the AST
+ */
+ initialState.transform(pair -> new ConstructorState<>(
+ pair.bindLeft(queue -> {
+ queue.push(newAST);
+
+ return new Pair<>(queue, newAST);
+ })
+ )
+ );
+ }
+ }
+} \ No newline at end of file