/*
* 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.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
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.MethodVisitor;
public class DeclarationExpressionTransformer extends ExprTransformer<DeclarationExpression> {
public Expression transform(DeclarationExpression exp, final CompilerTransformer compiler) {
if (!(exp.getLeftExpression() instanceof VariableExpression)) {
compiler.addError("Variable name expected", exp);
}
final VariableExpression ve = (VariableExpression) exp.getLeftExpression();
if (exp.getAnnotations() != null)
ve.addAnnotations(exp.getAnnotations());
if (ve.getOriginType() != ve.getType())
ve.setType(ve.getOriginType());
if (!ve.isDynamicTyped()) {
if (ClassHelper.isPrimitiveType(ve.getType()) && (exp.getRightExpression() instanceof ConstantExpression)) {
ConstantExpression constantExpression = (ConstantExpression) exp.getRightExpression();
if (constantExpression.getValue() == null) {
exp.setRightExpression(new ConstantExpression(0));
}
}
CastExpression cast = new CastExpression(ve.getType(), exp.getRightExpression());
cast.setSourcePosition(exp.getRightExpression());
exp.setRightExpression(cast);
}
BytecodeExpr right = (BytecodeExpr) compiler.transform(exp.getRightExpression());
if (right.getType() == TypeUtil.NULL_TYPE && ClassHelper.isPrimitiveType(ve.getType())) {
final ConstantExpression cnst = new ConstantExpression(0);
cnst.setSourcePosition(exp);
right = (BytecodeExpr) compiler.transform(cnst);
}
if (hasFieldAnnotation(ve)) {
ClassNode type;
if (!ve.isDynamicTyped()) {
type = ve.getType();
} else {
type = right.getType();
}
FieldNode fieldNode = compiler.classNode.addField(compiler.methodNode.getName() + "$" + ve.getName(), ACC_PRIVATE, type, exp.getRightExpression());
fieldNode.addAnnotation(new AnnotationNode(TypeUtil.NO_EXTERNAL_INITIALIZATION));
ve.setAccessedVariable(fieldNode);
return new BytecodeExpr(exp, TypeUtil.NULL_TYPE) {
protected void compile(MethodVisitor mv) {
mv.visitInsn(ACONST_NULL);
}
};
}
else {
if (!ve.isDynamicTyped()) {
if (ve.getType().equals(right.getType().redirect()) &&
ve.getType().getGenericsTypes() == null) {
ve.setType(right.getType()); //this is safe as long as generics are variant in type parameter.
} else {
right = compiler.cast(right, ve.getType());
}
return new Static(exp, ve, right, compiler);
} else {
right = compiler.transformSynthetic(right);
// let's try local type inference
compiler.getLocalVarInferenceTypes().add(ve, right.getType());
return new Dynamic(exp, right, compiler, ve);
}
}
}
public static boolean hasFieldAnnotation(VariableExpression ve) {
for (AnnotationNode node : ve.getAnnotations()) {
if ("Field".equals(node.getClassNode().getName()))
return true;
if ("groovy.lang.Field".equals(node.getClassNode().getName()))
return true;
}
return false;
}
private static class Static extends BytecodeExpr {
private final VariableExpression ve;
private final BytecodeExpr right;
private final CompilerTransformer compiler;
public Static(DeclarationExpression exp, VariableExpression ve, BytecodeExpr right, CompilerTransformer compiler) {
super(exp, ve.getType());
this.ve = ve;
this.right = right;
this.compiler = compiler;
}
protected void compile(MethodVisitor mv) {
right.visit(mv);
box(right.getType(), mv);
unbox(ve.getType(), mv);
dup(ve.getType(), mv);
compiler.compileStack.defineVariable(ve, true);
}
}
private static class Dynamic extends BytecodeExpr {
private final BytecodeExpr right;
private final CompilerTransformer compiler;
private final VariableExpression ve;
public Dynamic(DeclarationExpression exp, BytecodeExpr right, CompilerTransformer compiler, VariableExpression ve) {
super(exp, right.getType());
this.right = right;
this.compiler = compiler;
this.ve = ve;
}
protected void compile(MethodVisitor mv) {
right.visit(mv);
dup(right.getType(), mv);
compiler.compileStack.defineTypeInferenceVariable(ve, right.getType());
}
}
}