package bjc.utils.parserutils; import java.util.Deque; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; import bjc.utils.data.IHolder; import bjc.utils.data.IPair; import bjc.utils.data.Pair; import bjc.utils.funcdata.ITree; import bjc.utils.funcdata.Tree; final class TokenTransformer implements Consumer { private final class OperatorHandler implements UnaryOperator>, ITree>> { private T element; public OperatorHandler(T element) { this.element = element; } @Override public IPair>, ITree> apply( IPair>, ITree> pair) { return pair.bind((queuedASTs, currentAST) -> { return handleOperator(queuedASTs); }); } private IPair>, ITree> handleOperator( Deque> queuedASTs) { ITree newAST; if (isSpecialOperator.test(element)) { newAST = handleSpecialOperator.apply(element) .apply(queuedASTs); } else { if (queuedASTs.size() < 2) { throw new IllegalStateException( "Attempted to parse binary operator without enough operands.\n" + "Problem operator is " + element + "\nPossible operand is: \n\t" + queuedASTs.peek()); } ITree rightAST = queuedASTs.pop(); ITree leftAST = queuedASTs.pop(); newAST = new Tree<>(element, leftAST, rightAST); } queuedASTs.push(newAST); return new Pair<>(queuedASTs, newAST); } } private IHolder>, ITree>> initialState; private Predicate operatorPredicate; private Predicate isSpecialOperator; private Function>, ITree>> handleSpecialOperator; public TokenTransformer( IHolder>, ITree>> initialState, Predicate operatorPredicate, Predicate isSpecialOperator, Function>, ITree>> handleSpecialOperator) { this.initialState = initialState; this.operatorPredicate = operatorPredicate; this.isSpecialOperator = isSpecialOperator; this.handleSpecialOperator = handleSpecialOperator; } @Override public void accept(T element) { if (operatorPredicate.test(element)) { initialState.transform(new OperatorHandler(element)); } else { ITree newAST = new Tree<>(element); initialState.doWith((pair) -> { pair.doWith((queue, currentAST) -> { queue.push(newAST); }); }); initialState.transform((pair) -> { return pair.bind((queue, currentAST) -> { return new Pair<>(queue, newAST); }); }); } } }