/* * 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.bytecode; import org.codehaus.groovy.ast.ASTNode; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.syntax.Token; import org.codehaus.groovy.syntax.Types; import org.mbte.groovypp.compiler.CompilerTransformer; import org.mbte.groovypp.compiler.PresentationUtil; import org.mbte.groovypp.compiler.TypeUtil; import org.mbte.groovypp.compiler.Register; import org.mbte.groovypp.compiler.transformers.ListExpressionTransformer; import org.mbte.groovypp.compiler.transformers.MapExpressionTransformer; import org.objectweb.asm.MethodVisitor; public class ResolvedVarBytecodeExpr extends ResolvedLeftExpr { private final VariableExpression ve; private final Register var; public ResolvedVarBytecodeExpr(ClassNode type, VariableExpression ve, CompilerTransformer compiler) { super(ve, type); this.ve = ve; var = compiler.compileStack.getRegister(ve.getName(), true); } protected void compile(MethodVisitor mv) { load(getType(), var.getIndex(), mv); } public BytecodeExpr createAssign(ASTNode parent, BytecodeExpr right, CompilerTransformer compiler) { final ClassNode vtype; if (ve.isDynamicTyped()) { right = compiler.transformSynthetic(right); vtype = right.getType(); if (!compiler.getLocalVarInferenceTypes().add(ve, vtype)) { compiler.addError("IIlegal inference inside the loop. Consider making the variable's type explicit.", ve); } } else { vtype = ve.getType(); right = compiler.cast(right, vtype); } final BytecodeExpr finalRight = right; return new BytecodeExpr(parent, vtype) { protected void compile(MethodVisitor mv) { finalRight.visit(mv); if (ClassHelper.isPrimitiveType(finalRight.getType()) && !ClassHelper.isPrimitiveType(vtype)) box(finalRight.getType(), mv); store(vtype, var.getIndex(), mv); load(vtype, var.getIndex(), mv); } }; } public BytecodeExpr createBinopAssign(ASTNode parent, Token method, final BytecodeExpr right, CompilerTransformer compiler) { final BinaryExpression op = new BinaryExpression(this, method, right); op.setSourcePosition(parent); return createAssign(parent, (BytecodeExpr) compiler.transform(op), compiler); } public BytecodeExpr createPrefixOp(ASTNode exp, final int type, CompilerTransformer compiler) { final Register var = compiler.compileStack.getRegister(ve.getName(), false); if (var != null && var.getType().equals(ClassHelper.int_TYPE)) { return new BytecodeExpr(exp, ClassHelper.int_TYPE) { protected void compile(MethodVisitor mv) { mv.visitIincInsn(var.getIndex(), type == Types.PLUS_PLUS ? 1 : -1); mv.visitVarInsn(ILOAD, var.getIndex()); } }; } ClassNode vtype = compiler.getLocalVarInferenceTypes().get(ve); if (vtype == null) vtype = var.getType(); if (TypeUtil.isNumericalType(vtype) && !vtype.equals(TypeUtil.Number_TYPE)) { return new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { final ClassNode primType = ClassHelper.getUnwrapper(getType()); load(getType(), var.getIndex(), mv); if (getType() != primType) unbox(primType, mv); incOrDecPrimitive(primType, type, mv); if (getType() != primType) box(primType, mv); dup(getType(), mv); store(getType(), var.getIndex(), mv); } }; } if (ClassHelper.isPrimitiveType(vtype)) vtype = TypeUtil.wrapSafely(vtype); String methodName = type == Types.PLUS_PLUS ? "next" : "previous"; final MethodNode methodNode = compiler.findMethod(vtype, methodName, ClassNode.EMPTY_ARRAY, false); if (methodNode == null) { compiler.addError("Cannot find method " + methodName + "() for type " + PresentationUtil.getText(vtype), exp); return null; } final BytecodeExpr nextCall = (BytecodeExpr) compiler.transform(new MethodCallExpression( new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { load(var.getType(), var.getIndex(), mv); } }, methodName, new ArgumentListExpression() )); return new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { nextCall.visit(mv); dup(getType(), mv); store(var.getType(), var.getIndex(), mv); } }; } public BytecodeExpr createPostfixOp(ASTNode exp, final int type, CompilerTransformer compiler) { final Register var = compiler.compileStack.getRegister(ve.getName(), false); if (var != null && var.getType().equals(ClassHelper.int_TYPE)) { return new BytecodeExpr(exp, ClassHelper.int_TYPE) { protected void compile(MethodVisitor mv) { mv.visitVarInsn(ILOAD, var.getIndex()); mv.visitIincInsn(var.getIndex(), type == Types.PLUS_PLUS ? 1 : -1); } }; } ClassNode vtype = compiler.getLocalVarInferenceTypes().get(ve); if (vtype == null) vtype = var.getType(); if (TypeUtil.isNumericalType(vtype) && !vtype.equals(TypeUtil.Number_TYPE)) { return new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { final ClassNode primType = ClassHelper.getUnwrapper(getType()); load(getType(), var.getIndex(), mv); dup(getType(), mv); if (getType() != primType) unbox(primType, mv); incOrDecPrimitive(primType, type, mv); if (getType() != primType) box(primType, mv); store(getType(), var.getIndex(), mv); } }; } if (ClassHelper.isPrimitiveType(vtype)) vtype = TypeUtil.wrapSafely(vtype); String methodName = type == Types.PLUS_PLUS ? "next" : "previous"; final MethodNode methodNode = compiler.findMethod(vtype, methodName, ClassNode.EMPTY_ARRAY, false); if (methodNode == null) { compiler.addError("Cannot find method " + methodName + "() for type " + PresentationUtil.getText(vtype), exp); return null; } final BytecodeExpr nextCall = (BytecodeExpr) compiler.transform(new MethodCallExpression( new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { load(var.getType(), var.getIndex(), mv); dup(getType(), mv); } }, methodName, new ArgumentListExpression() )); return new BytecodeExpr(exp, vtype) { protected void compile(MethodVisitor mv) { nextCall.visit(mv); store(getType(), var.getIndex(), mv); } }; } }