package me.august.lumen.compile.parser.ast.expr;
import me.august.lumen.common.BytecodeUtil;
import me.august.lumen.compile.codegen.BuildContext;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
public class MultExpr extends BinaryExpression {
public enum Op {
MULT, DIV, REM
}
private Op op;
private Type type;
public MultExpr(Expression left, Expression right, Op op) {
super(left, right);
this.op = op;
}
@Override
public Type expressionType() {
if (type != null) return type;
Type leftType = left.expressionType();
Type rightType = right.expressionType();
if (BytecodeUtil.isPrimitive(leftType) && BytecodeUtil.isPrimitive(rightType)) {
Type widest = BytecodeUtil.widest(leftType, rightType);
// if the widest of the two is less than int,
// promote to int
if (widest.getSort() < Type.INT) {
widest = Type.INT_TYPE;
}
return (type = widest);
}
throw new RuntimeException("Incompatible operands: " + leftType + ", " + rightType);
}
@Override
public void generate(MethodVisitor visitor, BuildContext context) {
int opcode;
Type leftType = left.expressionType();
Type rightType = right.expressionType();
left.generate(visitor, context);
opcode = BytecodeUtil.castNumberOpcode(leftType, expressionType());
if (opcode >= 0)
visitor.visitInsn(opcode);
right.generate(visitor, context);
opcode = BytecodeUtil.castNumberOpcode(rightType, expressionType());
if (opcode >= 0)
visitor.visitInsn(opcode);
if (op == Op.MULT) {
opcode = BytecodeUtil.multiplyInstruction(expressionType());
} else if (op == Op.DIV) {
opcode = BytecodeUtil.divisionInstruction(expressionType());
} else { // must be REM
opcode = BytecodeUtil.remainderInstruction(expressionType());
}
visitor.visitInsn(opcode);
}
}