/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.ir.compiler.bytecode.expression;
import gw.internal.gosu.ir.compiler.bytecode.AbstractBytecodeCompiler;
import gw.internal.gosu.ir.compiler.bytecode.IRBytecodeContext;
import gw.internal.gosu.ir.compiler.bytecode.IRBytecodeCompiler;
import gw.lang.ir.expression.IREqualityExpression;
import gw.lang.ir.expression.IRNullLiteral;
import gw.lang.ir.IRType;
import gw.lang.ir.IRExpression;
import gw.internal.ext.org.objectweb.asm.Label;
import gw.internal.ext.org.objectweb.asm.Opcodes;
import gw.internal.ext.org.objectweb.asm.MethodVisitor;
public class IREqualityExpressionCompiler extends AbstractBytecodeCompiler {
public static void compile( IREqualityExpression expression, IRBytecodeContext context ) {
if (expression.getLhs() instanceof IRNullLiteral || expression.getRhs() instanceof IRNullLiteral) {
compareToNull( expression.isEquals(), expression.getLhs() instanceof IRNullLiteral ? expression.getRhs() : expression.getLhs(), context );
} else if (expression.getLhs().getType().isPrimitive()) {
if (!expression.getLhs().getType().equals(expression.getRhs().getType())) {
throw new IllegalArgumentException("Equality expression comparing two different primitive types :" +
expression.getLhs().getType().getName() + " and " + expression.getRhs().getType().getName());
}
IRType lhsType = expression.getLhs().getType();
if (lhsType.isBoolean() || lhsType.isByte() || lhsType.isChar() || lhsType.isShort() || lhsType.isInt()) {
compareInts( expression.isEquals(), expression.getLhs(), expression.getRhs(), context );
} else if (lhsType.isLong()) {
compareLongs( expression.isEquals(), expression.getLhs(), expression.getRhs(), context );
} else if (lhsType.isDouble()) {
compareDoubles( expression.isEquals(), expression.getLhs(), expression.getRhs(), context );
} else if (lhsType.isFloat()) {
compareFloats( expression.isEquals(), expression.getLhs(), expression.getRhs(), context );
} else {
System.out.println("Unexpected primitive type " + lhsType.getName());
}
} else {
compareObjects( expression.isEquals(), expression.getLhs(), expression.getRhs(), context );
}
}
private static void compareToNull( boolean equals, IRExpression expr, IRBytecodeContext context ) {
MethodVisitor mv = context.getMv();
IRBytecodeCompiler.compileIRExpression( expr, context );
compare( mv, equals ? Opcodes.IFNULL : Opcodes.IFNONNULL );
}
private static void compareInts( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context ) {
MethodVisitor mv = context.getMv();
IRBytecodeCompiler.compileIRExpression( lhs, context );
IRBytecodeCompiler.compileIRExpression( rhs, context );
compare( mv, equals ? Opcodes.IF_ICMPEQ : Opcodes.IF_ICMPNE );
}
private static void compareLongs( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context ) {
compareNonIntPrimitives( equals, lhs, rhs, context, Opcodes.LCMP );
}
private static void compareDoubles( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context ) {
compareNonIntPrimitives( equals, lhs, rhs, context, Opcodes.DCMPL );
}
private static void compareFloats( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context ) {
compareNonIntPrimitives( equals, lhs, rhs, context, Opcodes.FCMPL );
}
private static void compareNonIntPrimitives( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context, int compareOp ) {
MethodVisitor mv = context.getMv();
IRBytecodeCompiler.compileIRExpression( lhs, context );
IRBytecodeCompiler.compileIRExpression( rhs, context );
mv.visitInsn( compareOp );
compare( mv, equals ? Opcodes.IFEQ : Opcodes.IFNE );
}
private static void compareObjects( boolean equals, IRExpression lhs, IRExpression rhs, IRBytecodeContext context ) {
MethodVisitor mv = context.getMv();
IRBytecodeCompiler.compileIRExpression( lhs, context );
IRBytecodeCompiler.compileIRExpression( rhs, context );
compare( mv, equals ? Opcodes.IF_ACMPEQ : Opcodes.IF_ACMPNE );
}
private static void compare( MethodVisitor mv, int opcode ) {
Label labelTrue = new Label();
mv.visitJumpInsn( opcode, labelTrue );
mv.visitInsn( Opcodes.ICONST_0 );
Label labelFalse = new Label();
mv.visitJumpInsn( Opcodes.GOTO, labelFalse );
mv.visitLabel( labelTrue );
mv.visitInsn( Opcodes.ICONST_1 );
mv.visitLabel( labelFalse );
}
}