package com.hypixel.hytale.server.npc.util.expression.compile;
import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
import com.hypixel.hytale.server.npc.util.expression.Expression;
import com.hypixel.hytale.server.npc.util.expression.Scope;
import com.hypixel.hytale.server.npc.util.expression.ValueType;
import com.hypixel.hytale.server.npc.util.expression.compile.ast.AST;
import com.hypixel.hytale.server.npc.util.expression.compile.ast.ASTOperand;
import com.hypixel.hytale.server.npc.util.expression.compile.ast.ASTOperator;
import com.hypixel.hytale.server.npc.util.expression.compile.ast.ASTOperatorFunctionCall;
import com.hypixel.hytale.server.npc.util.expression.compile.ast.ASTOperatorTuple;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.text.ParseException;
import java.util.List;
import java.util.Stack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class CompileContext implements Parser.ParsedTokenConsumer {
private final Parser parser;
private final Stack<AST> operandStack;
@Nonnull
private final ExecutionContext executionContext;
private Scope scope;
private List<ExecutionContext.Instruction> instructions;
private ValueType resultType;
public CompileContext() {
this.parser = new Parser(Expression.getLexerInstance());
this.operandStack = new Stack();
this.resultType = ValueType.VOID;
this.executionContext = new ExecutionContext();
}
public CompileContext(Scope scope) {
this();
this.scope = scope;
}
public Scope getScope() {
return this.scope;
}
@Nonnull
public Stack<AST> getOperandStack() {
return this.operandStack;
}
@Nonnull
public ExecutionContext getExecutionContext() {
return this.executionContext;
}
public ValueType compile(@Nonnull String expression, Scope compileScope, boolean fullResolve) {
return this.compile0(expression, compileScope, fullResolve, (List)null);
}
public ValueType compile(@Nonnull String expression, Scope compileScope, boolean fullResolve, List<ExecutionContext.Instruction> instructions) {
ValueType valueType = this.compile0(expression, compileScope, fullResolve, instructions);
this.setInstructions((List)null);
return valueType;
}
protected ValueType compile0(@Nonnull String expression, Scope compileScope, boolean fullResolve, List<ExecutionContext.Instruction> instructions) {
Scope saveScope = this.scope;
Scope oldScope = this.executionContext.setScope(compileScope);
this.scope = compileScope;
this.setInstructions(instructions);
this.compile(expression, fullResolve);
this.executionContext.setScope(oldScope);
this.scope = saveScope;
return this.resultType;
}
public ValueType compile(@Nonnull String expression, boolean fullResolve) {
try {
this.operandStack.clear();
this.resultType = ValueType.VOID;
if (this.instructions == null) {
this.instructions = new ObjectArrayList<ExecutionContext.Instruction>();
}
this.instructions.clear();
this.parser.parse(expression, this);
this.resultType = ((AST)this.operandStack.getFirst()).genCode(this.instructions, fullResolve ? this.scope : null);
return this.resultType;
} catch (Throwable t) {
throw new IllegalStateException("Error compiling expression '" + expression + "': " + t.getMessage(), t);
}
}
public List<ExecutionContext.Instruction> getInstructions() {
return this.instructions;
}
public void setInstructions(List<ExecutionContext.Instruction> instructionList) {
this.instructions = instructionList;
}
public ValueType getResultType() {
return this.resultType;
}
@Nullable
public ExecutionContext.Operand getAsOperand() {
if (this.operandStack.size() != 1) {
throw new IllegalArgumentException("There must be 1 element on stack to get as operand");
} else {
AST ast = (AST)this.operandStack.getFirst();
return ast.isConstant() ? ast.asOperand() : null;
}
}
public void checkResultType(ValueType type) {
if (type == ValueType.VOID) {
throw new IllegalArgumentException("Result type can't be void");
} else if (this.resultType == ValueType.VOID) {
throw new IllegalArgumentException("Compiled expression result type can't be void");
} else if (type != this.resultType) {
String var10002 = String.valueOf(type);
throw new IllegalStateException("Result type expected is " + var10002 + " but got " + String.valueOf(this.resultType));
}
}
public void pushOperand(@Nonnull Parser.ParsedToken parsedToken) {
this.operandStack.push(ASTOperand.createFromParsedToken(parsedToken, this));
}
public void processOperator(@Nonnull Parser.ParsedToken operator) throws ParseException {
ASTOperator.fromParsedOperator(operator, this);
}
public void processFunction(int argumentCount) throws ParseException {
ASTOperatorFunctionCall.fromParsedFunction(argumentCount, this);
}
public void processTuple(@Nonnull Parser.ParsedToken openingToken, int argumentCount) {
ASTOperatorTuple.fromParsedTuple(openingToken, argumentCount, this);
}
public void done() {
if (this.operandStack.size() != 1) {
throw new IllegalStateException("Need exactly one returned value in expression");
}
}
}