/* * 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.expr.*; import org.codehaus.groovy.classgen.BytecodeHelper; import org.codehaus.groovy.classgen.BytecodeExpression; import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; import org.mbte.groovypp.compiler.CompilerTransformer; import org.mbte.groovypp.compiler.TypeUtil; import org.mbte.groovypp.compiler.bytecode.BytecodeExpr; import org.mbte.groovypp.compiler.bytecode.ResolvedMethodBytecodeExpr; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.objectweb.asm.MethodVisitor; import java.util.IdentityHashMap; public abstract class ExprTransformer<T extends Expression> implements Opcodes { private static IdentityHashMap<Class, ExprTransformer> transformers = new IdentityHashMap<Class, ExprTransformer>(); static { transformers.put(CastExpression.class, new CastExpressionTransformer()); transformers.put(ClassExpression.class, new ClassExpressionTransformer()); transformers.put(ConstantExpression.class, new ConstantExpressionTransformer()); transformers.put(ListExpression.class, new ListExpressionTransformer()); transformers.put(MapExpression.class, new MapExpressionTransformer()); transformers.put(SpreadExpression.class, new SpreadExpressionTransformer()); transformers.put(VariableExpression.class, new VariableExpressionTransformer()); transformers.put(DeclarationExpression.class, new DeclarationExpressionTransformer()); transformers.put(ClosureExpression.class, new ClosureExpressionTransformer()); transformers.put(MethodCallExpression.class, new MethodCallExpressionTransformer()); transformers.put(PostfixExpression.class, new PostfixExpressionTransformer()); transformers.put(PrefixExpression.class, new PrefixExpressionTransformer()); transformers.put(PropertyExpression.class, new PropertyExpressionTransformer()); transformers.put(BinaryExpression.class, new BinaryExpressionTransformer()); transformers.put(GStringExpression.class, new GStringExpressionTransformer()); transformers.put(ConstructorCallExpression.class, new ConstructorCallExpressionTransformer()); transformers.put(RangeExpression.class, new RangeExpressionTransformer()); transformers.put(FieldExpression.class, new FieldExpressionTransformer()); transformers.put(UnaryMinusExpression.class, new UnaryMinusExpressionTransformer()); transformers.put(UnaryPlusExpression.class, new UnaryPlusExpressionTransformer()); transformers.put(ArrayExpression.class, new ArrayExpressionTransformer()); transformers.put(BitwiseNegationExpression.class, new BitwiseNegationExpressionTransformer()); transformers.put(AttributeExpression.class, new AttributeExpressionTransformer()); transformers.put(NamedArgumentListExpression.class, new NamedArgumentListExpressionTransformer()); transformers.put(MethodPointerExpression.class, new MethodPointerExpressionTransformer()); final BooleanExpressionTransformer bool = new BooleanExpressionTransformer(); transformers.put(BooleanExpression.class, bool); transformers.put(NotExpression.class, bool); final TernaryExpressionTransformer ternary = new TernaryExpressionTransformer(); transformers.put(TernaryExpression.class, ternary); transformers.put(ElvisOperatorExpression.class, ternary); } public static Expression transformExpression(final Expression exp, CompilerTransformer compiler) { if (exp instanceof BytecodeExpression) { if (exp instanceof BytecodeExpr) return exp; return new BytecodeExpr(exp, exp.getType()) { protected void compile(MethodVisitor mv) { ((BytecodeExpression)exp).visit(mv); } }; } ExprTransformer t = transformers.get(exp.getClass()); if (t == null) return compiler.transformImpl(exp); return t.transform(exp, compiler); } public static BytecodeExpr transformLogicalExpression(Expression exp, CompilerTransformer compiler, Label label, boolean onTrue) { if (exp instanceof StaticMethodCallExpression) { StaticMethodCallExpression smce = (StaticMethodCallExpression) exp; MethodCallExpression mce = new MethodCallExpression( new ClassExpression(smce.getOwnerType()), smce.getMethod(), smce.getArguments()); mce.setSourcePosition(smce); return transformLogicalExpression(mce, compiler, label, onTrue); } ExprTransformer t = transformers.get(exp.getClass()); return t.transformLogical(exp, compiler, label, onTrue); } public abstract Expression transform(T exp, CompilerTransformer compiler); public BytecodeExpr transformLogical(T exp, CompilerTransformer compiler, final Label label, final boolean onTrue) { final BytecodeExpr be; be = (BytecodeExpr) transform(exp, compiler); final ClassNode type = be.getType(); if (type == ClassHelper.VOID_TYPE) { return be; } if (ClassHelper.isPrimitiveType(type)) { return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) { protected void compile(MethodVisitor mv) { be.visit(mv); if (type == ClassHelper.byte_TYPE || type == ClassHelper.short_TYPE || type == ClassHelper.char_TYPE || type == ClassHelper.boolean_TYPE || type == ClassHelper.int_TYPE) { } else if (type == ClassHelper.long_TYPE) { mv.visitInsn(L2I); } else if (type == ClassHelper.float_TYPE) { mv.visitInsn(F2I); } else if (type == ClassHelper.double_TYPE) { mv.visitInsn(D2I); } mv.visitJumpInsn(onTrue ? IFNE : IFEQ, label); } }; } else { MethodCallExpression safeCall = new MethodCallExpression(new BytecodeExpr(exp, be.getType()) { protected void compile(MethodVisitor mv) { } }, "asBoolean", ArgumentListExpression.EMPTY_ARGUMENTS); safeCall.setSourcePosition(exp); final ResolvedMethodBytecodeExpr call = (ResolvedMethodBytecodeExpr) compiler.transform(safeCall); if (!call.getType().equals(ClassHelper.boolean_TYPE)) compiler.addError("asBoolean should return 'boolean'", exp); if(call.getMethodNode().getDeclaringClass().equals(ClassHelper.OBJECT_TYPE)) { // fast path return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) { protected void compile(MethodVisitor mv) { be.visit(mv); mv.visitJumpInsn( onTrue ? IFNONNULL : IFNULL, label); } }; } else { return new BytecodeExpr(exp, ClassHelper.VOID_TYPE) { protected void compile(MethodVisitor mv) { be.visit(mv); mv.visitInsn(DUP); Label nullLabel = new Label(), endLabel = new Label (); mv.visitJumpInsn(IFNULL, nullLabel); call.visit(mv); if (onTrue) { mv.visitJumpInsn(IFEQ, endLabel); mv.visitJumpInsn(GOTO, label); mv.visitLabel(nullLabel); mv.visitInsn(POP); } else { mv.visitJumpInsn(IFNE, endLabel); mv.visitJumpInsn(GOTO, label); mv.visitLabel(nullLabel); mv.visitInsn(POP); mv.visitJumpInsn(GOTO, label); } mv.visitLabel(endLabel); } }; } } } private static final String DTT = BytecodeHelper.getClassInternalName(DefaultTypeTransformation.class.getName()); }