/* * Copyright 2009-2010 MBTE Sweden AB. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mbte.groovypp.compiler.transformers; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.expr.*; import org.mbte.groovypp.compiler.CompilerTransformer; import org.mbte.groovypp.compiler.TypeUtil; import org.mbte.groovypp.compiler.bytecode.BytecodeExpr; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class TernaryExpressionTransformer extends ExprTransformer<TernaryExpression>{ public Expression transform(TernaryExpression exp, CompilerTransformer compiler) { InnerClassNode newType = new InnerClassNode(compiler.classNode, compiler.getNextClosureName(), ACC_PUBLIC|ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE); newType.setInterfaces(new ClassNode[] {TypeUtil.TTERNARY}); final UntransformedTernaryExpr untransformed = new UntransformedTernaryExpr(exp, newType); return untransformed.improve(compiler); } public static class UntransformedTernaryExpr extends BytecodeExpr { public TernaryExpression exp; public UntransformedTernaryExpr(TernaryExpression exp, ClassNode type) { super(exp, type); this.exp = exp; } protected void compile(MethodVisitor mv) { throw new UnsupportedOperationException(); } public BytecodeExpr transform(CompilerTransformer compiler) { if (exp instanceof ElvisOperatorExpression) { return transfromElvis((ElvisOperatorExpression)exp, compiler); } else { return transfromTernary(exp, compiler); } } private BytecodeExpr transfromTernary(TernaryExpression te, CompilerTransformer compiler) { final Label elseLabel = new Label(); final BytecodeExpr condition = compiler.transformLogical(te.getBooleanExpression().getExpression(), elseLabel, false); final BytecodeExpr trueE = (BytecodeExpr) compiler.transform(te.getTrueExpression()); final BytecodeExpr falseE = (BytecodeExpr) compiler.transform(te.getFalseExpression()); final ClassNode type = TypeUtil.commonType(trueE.getType(), falseE.getType()); final BytecodeExpr finalTrueE = compiler.cast(trueE, type); final BytecodeExpr finalFalseE = compiler.cast(falseE, type); return new BytecodeExpr(te, type) { protected void compile(MethodVisitor mv) { condition.visit(mv); finalTrueE.visit(mv); Label endLabel = new Label(); mv.visitJumpInsn(GOTO, endLabel); mv.visitLabel(elseLabel); finalFalseE.visit(mv); mv.visitLabel(endLabel); } }; } private BytecodeExpr transfromElvis(ElvisOperatorExpression ee, CompilerTransformer compiler) { ee = (ElvisOperatorExpression) ee.transformExpression(compiler); final ElvisOperatorExpression eee = ee; final BytecodeExpr be = (BytecodeExpr) ee.getBooleanExpression().getExpression(); final BytecodeExpr brunch = compiler.castToBoolean( new BytecodeExpr(be, be.getType()){ protected void compile(MethodVisitor mv) { be.visit(mv); dup(be.getType(), mv); } }, ClassHelper.boolean_TYPE); return new Elvis(ee, eee, brunch); } public Expression improve(CompilerTransformer compiler) { if (exp instanceof ElvisOperatorExpression) return transform(compiler); final BytecodeExpr trueE = (BytecodeExpr) compiler.transform(exp.getTrueExpression()); final BytecodeExpr falseE = (BytecodeExpr) compiler.transform(exp.getFalseExpression()); if(trueE instanceof MapExpressionTransformer.UntransformedMapExpr || trueE instanceof ListExpressionTransformer.UntransformedListExpr || trueE instanceof UntransformedTernaryExpr || falseE instanceof MapExpressionTransformer.UntransformedMapExpr || falseE instanceof ListExpressionTransformer.UntransformedListExpr || falseE instanceof UntransformedTernaryExpr) { final TernaryExpression newExp = new TernaryExpression(exp.getBooleanExpression(), trueE, falseE); newExp.setSourcePosition(exp); exp = newExp; return this; } else { return transform(compiler); } } private static class Elvis extends BytecodeExpr { private final ElvisOperatorExpression eee; private BytecodeExpr branch; public Elvis(ElvisOperatorExpression ee, ElvisOperatorExpression eee, BytecodeExpr branch) { super(ee, TypeUtil.commonType(ee.getBooleanExpression().getExpression().getType(), ee.getFalseExpression().getType())); this.eee = eee; this.branch = branch; } protected void compile(MethodVisitor mv) { branch.visit(mv); Label elseLabel = new Label(); mv.visitJumpInsn(Opcodes.IFEQ, elseLabel); final BytecodeExpr be = (BytecodeExpr) eee.getBooleanExpression().getExpression(); box (be.getType(), mv); cast(TypeUtil.wrapSafely(be.getType()), TypeUtil.wrapSafely(getType()), mv); unbox(getType(), mv); Label endLabel = new Label(); mv.visitJumpInsn(GOTO, endLabel); mv.visitLabel(elseLabel); final BytecodeExpr falseExp = (BytecodeExpr) eee.getFalseExpression(); pop(be.getType(), mv); falseExp.visit(mv); box (falseExp.getType(), mv); cast(TypeUtil.wrapSafely(falseExp.getType()), TypeUtil.wrapSafely(getType()), mv); unbox(getType(), mv); mv.visitLabel(endLabel); } } } }