/*
* 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.Expression;
import org.codehaus.groovy.ast.expr.MapEntryExpression;
import org.codehaus.groovy.ast.expr.MapExpression;
import org.codehaus.groovy.classgen.BytecodeHelper;
import org.mbte.groovypp.compiler.CompilerTransformer;
import org.mbte.groovypp.compiler.TypeUtil;
import org.mbte.groovypp.compiler.bytecode.BytecodeExpr;
import org.objectweb.asm.MethodVisitor;
import java.util.List;
public class MapExpressionTransformer extends ExprTransformer<MapExpression> {
public Expression transform(final MapExpression exp, final CompilerTransformer compiler) {
InnerClassNode newType = new InnerClassNode(compiler.classNode, compiler.getNextClosureName(), ACC_PUBLIC|ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE);
newType.setModule(compiler.classNode.getModule());
newType.setInterfaces(new ClassNode[] {TypeUtil.TMAP});
return new UntransformedMapExpr(exp, newType);
}
public static class UntransformedMapExpr extends BytecodeExpr {
public final MapExpression exp;
public UntransformedMapExpr(MapExpression exp, ClassNode type) {
super(exp, type);
this.exp = exp;
}
protected void compile(MethodVisitor mv) {
throw new UnsupportedOperationException();
}
public BytecodeExpr transform(CompilerTransformer compiler) {
return new TransformedMapExpr(exp, TypeUtil.LINKED_HASH_MAP_TYPE, compiler);
}
}
public static class TransformedMapExpr extends BytecodeExpr {
private final MapExpression exp;
public TransformedMapExpr(MapExpression exp, ClassNode type, CompilerTransformer compiler) {
super(exp, type);
this.exp = exp;
final List<MapEntryExpression> list = exp.getMapEntryExpressions();
if (list.size() > 0) {
ClassNode keyArg = TypeUtil.NULL_TYPE;
ClassNode valueArg = TypeUtil.NULL_TYPE;
for (int i = 0; i != list.size(); ++i) {
final MapEntryExpression me = list.get(i);
final Expression key = compiler.transformToGround(me.getKeyExpression());
final Expression value = compiler.transformToGround(me.getValueExpression());
MapEntryExpression nme = new MapEntryExpression(key, value);
keyArg = TypeUtil.commonType(keyArg, nme.getKeyExpression().getType());
valueArg = TypeUtil.commonType(valueArg, nme.getValueExpression().getType());
nme.setSourcePosition(me);
list.set(i, nme);
}
if (keyArg == TypeUtil.NULL_TYPE) keyArg = ClassHelper.OBJECT_TYPE;
if (valueArg == TypeUtil.NULL_TYPE) valueArg = ClassHelper.OBJECT_TYPE;
setType(TypeUtil.withGenericTypes(getType(), keyArg, valueArg));
}
}
protected void compile(MethodVisitor mv) {
final List<MapEntryExpression> list = exp.getMapEntryExpressions();
mv.visitTypeInsn(NEW, BytecodeHelper.getClassInternalName(getType()));
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL,BytecodeHelper.getClassInternalName(getType()),"<init>","()V");
for (int i = 0; i != list.size(); ++i) {
mv.visitInsn(DUP);
final MapEntryExpression me = list.get(i);
final BytecodeExpr ke = (BytecodeExpr) me.getKeyExpression();
ke.visit(mv);
box(ke.getType(), mv);
final BytecodeExpr ve = (BytecodeExpr) me.getValueExpression();
ve.visit(mv);
box(ve.getType(), mv);
mv.visitMethodInsn(INVOKEINTERFACE,"java/util/Map","put","(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
mv.visitInsn(POP);
}
}
}
}