package bjc.utils.parserutils; import bjc.utils.data.IHolder; import bjc.utils.data.ITree; import bjc.utils.data.Pair; import bjc.utils.data.Tree; import bjc.utils.parserutils.TreeConstructor.ConstructorState; import bjc.utils.parserutils.TreeConstructor.QueueFlattener; import java.util.Deque; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; final class TokenTransformer implements Consumer { // Handle operators private final class OperatorHandler implements UnaryOperator> { private TokenType element; public OperatorHandler(TokenType element) { this.element = element; } @Override public ConstructorState apply(ConstructorState pair) { // Replace the current AST with the result of handling // an operator return new ConstructorState<>(pair.bindLeft(queuedASTs -> { return handleOperator(queuedASTs); })); } private ConstructorState handleOperator(Deque> queuedASTs) { // The AST we're going to hand back ITree 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) { 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 ITree right = queuedASTs.pop(); ITree 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); } } private IHolder> initialState; private Predicate operatorPredicate; private Predicate isSpecialOperator; private Function> handleSpecialOperator; // Create a new transformer public TokenTransformer(IHolder> initialState, Predicate operatorPredicate, Predicate isSpecialOperator, Function> handleSpecialOperator) { this.initialState = initialState; this.operatorPredicate = operatorPredicate; this.isSpecialOperator = isSpecialOperator; this.handleSpecialOperator = handleSpecialOperator; } @Override public void accept(TokenType element) { // Handle operators if(operatorPredicate.test(element)) { initialState.transform(new OperatorHandler(element)); } else { ITree newAST = new Tree<>(element); // Insert the new tree into the AST initialState.transform(pair -> { // Transform the pair, ignoring the current AST // in favor of the // one consisting of the current element return new ConstructorState<>(pair.bindLeft(queue -> { queue.push(newAST); return new Pair<>(queue, newAST); })); }); } } }