package openmods.calc.parsing;
import com.google.common.collect.PeekingIterator;
import openmods.calc.IExecutable;
import openmods.calc.parsing.IPostfixCompilerState.Result;
import openmods.utils.Stack;
public abstract class PostfixCompiler<E> implements ITokenStreamCompiler<E> {
@Override
public IExecutable<E> compile(PeekingIterator<Token> input) {
final Stack<IPostfixCompilerState<E>> stateStack = Stack.create();
stateStack.push(createInitialState());
while (input.hasNext()) {
final Token token = input.next();
if (token.type == TokenType.MODIFIER) {
stateStack.push(createStateForModifier(token.value));
} else if (token.type == TokenType.LEFT_BRACKET) {
stateStack.push(createStateForBracket(token.value));
} else {
final IPostfixCompilerState<E> currentState = stateStack.peek(0);
final Result result = currentState.acceptToken(token);
switch (result) {
case ACCEPTED_AND_FINISHED:
unwindStack(stateStack);
// fall-through
case ACCEPTED:
// NO-OP
break;
case REJECTED:
default:
throw new IllegalStateException("Token " + token + " not accepted in state " + currentState);
}
}
}
final IPostfixCompilerState<E> finalState = stateStack.popAndExpectEmptyStack();
return finalState.exit();
}
private void unwindStack(Stack<IPostfixCompilerState<E>> stateStack) {
IPostfixCompilerState<E> currentState = stateStack.pop();
UNWIND: while (true) {
final IExecutable<E> exitResult = currentState.exit();
currentState = stateStack.peek(0);
final Result acceptResult = currentState.acceptExecutable(exitResult);
switch (acceptResult) {
case ACCEPTED_AND_FINISHED:
stateStack.pop();
continue UNWIND;
case ACCEPTED:
break UNWIND;
case REJECTED:
default:
throw new IllegalStateException("Executable " + exitResult + " not accepted in state " + currentState);
}
}
}
protected abstract IPostfixCompilerState<E> createInitialState();
protected IPostfixCompilerState<E> createStateForModifier(String modifier) {
throw new UnsupportedOperationException(modifier);
}
protected IPostfixCompilerState<E> createStateForBracket(String bracket) {
throw new UnsupportedOperationException(bracket);
}
}