package mhfc.net.common.util.parsing.syntax.tree;
import java.util.List;
import java.util.Objects;
import mhfc.net.common.util.parsing.syntax.operators.BinaryOPWrapper;
import mhfc.net.common.util.parsing.syntax.operators.IBinaryOperator;
import mhfc.net.common.util.parsing.syntax.operators.IOperator;
public class AST extends UnaryAST {
// map userOp_id -> opid, highest bit = isPrefix
private final int[] publicIDToRealOpID;
// map value_id -> Class of value, for type safety
private final Class<?>[] valueClasses;
private final Class<?>[] publicClasses;
/* package */ AST(SyntaxBuilder builder) {
super(builder.validate());
List<SyntaxBuilder.ValueRegistration> valueReg = builder.getValues();
List<SyntaxBuilder.OperatorRemap> publicRemap = builder.getRemapPublicIDs();
publicIDToRealOpID = new int[publicRemap.size()];
publicClasses = new Class[publicRemap.size()];
valueClasses = new Class[valueReg.size()];
for (SyntaxBuilder.ValueRegistration val : valueReg) {
valueClasses[val.valueID] = val.clazz;
}
for (SyntaxBuilder.OperatorRemap remap : publicRemap) {
publicIDToRealOpID[remap.publicID] = toRemappedOP(remap.isDominantPrefix(), remap.getDominantID());
publicClasses[remap.publicID] = remap.clazz;
}
}
protected AST(AST structure) {
super(structure);
this.publicIDToRealOpID = structure.publicIDToRealOpID;
this.valueClasses = structure.valueClasses;
this.publicClasses = structure.publicClasses;
}
@Override
public void pushValue(int valueId, Object val) throws IllegalStateException {
super.pushValue(valueId, valueClasses[valueId].cast(val));
}
public void pushUnaryOperator(int publicID, IOperator<?, ?> operator) throws IllegalStateException {
publicClasses[publicID].cast(operator);
Objects.requireNonNull(operator);
int op = publicIDToRealOpID[publicID];
boolean isPrefix = isRemappedPrefixOP(op);
int realID = fromRemappedOP(op);
pushOperator(isPrefix, realID, operator);
}
public void pushBinaryOperator(int publicID, IBinaryOperator<?, ?, ?> operator) throws IllegalStateException {
Class<?> clazz = publicClasses[publicID];
Objects.requireNonNull(operator);
clazz.cast(operator);
int op = publicIDToRealOpID[publicID];
boolean isPrefix = isRemappedPrefixOP(op);
int realID = fromRemappedOP(op);
pushOperator(isPrefix, realID, BinaryOPWrapper.wrap(operator));
}
private int toRemappedOP(boolean isPrefix, int realID) {
return (realID & 0x7FFFFFFF) | (isPrefix ? 0x80000000 : 0);
}
private boolean isRemappedPrefixOP(int remapped) {
return (remapped & 0x80000000) != 0;
}
private int fromRemappedOP(int remapped) {
return (remapped & 0x7FFFFFFF);
}
/**
* Returns a new, fresh AST (with no values or operators pushed) but with the same syntax as this AST.<br>
* This is so that you can dispose of the {@link SyntaxBuilder} after finishing building it and still make fresh
* syntax trees.
*
* @return
*/
public AST makeFreshTree() {
return new AST(this);
}
}