org.mbte.groovypp.compiler.transformers.ExprTransformer.java Source code

Java tutorial

Introduction

Here is the source code for org.mbte.groovypp.compiler.transformers.ExprTransformer.java

Source

/*
 * 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());
}