提交 d17f095e 编写于 作者: D Dmitry Jemerov

namespace properties are mostly working

上级 c91cd748
......@@ -11,6 +11,7 @@ import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
......@@ -151,8 +152,9 @@ public class ClassCodegen {
}
private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) {
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext);
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen);
for (JetDeclaration declaration : aClass.getDeclarations()) {
if (declaration instanceof JetProperty) {
......
......@@ -370,6 +370,28 @@ public class ExpressionCodegen extends JetVisitor {
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
myStack.push(StackValue.local(index, typeMapper.mapType(outType)));
}
else if (descriptor instanceof PropertyDescriptor) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
JetNamespace ns = (JetNamespace) bindingContext.getDeclarationPsiElement(descriptor.getContainingDeclaration());
String owner = JetTypeMapper.jvmName(ns);
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
Method getter;
Method setter;
if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
getter = null;
setter = null;
}
else {
getter = typeMapper.mapGetterSignature(propertyDescriptor);
setter = typeMapper.mapSetterSignature(propertyDescriptor);
}
myStack.push(StackValue.property(descriptor.getName(), owner, typeMapper.mapType(outType), getter, setter));
}
else {
throw new UnsupportedOperationException("don't know how to generate non-namespace property reference " + descriptor);
}
}
else {
throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
}
......@@ -887,10 +909,7 @@ public class ExpressionCodegen extends JetVisitor {
int increment = op.getName().equals("inc") ? 1 : -1;
if (operand instanceof JetReferenceExpression) {
final int index = indexOfLocal((JetReferenceExpression) operand);
if (index < 0) {
throw new UnsupportedOperationException("don't know how to increment or decrement something which is not a local var");
}
if (isIntPrimitive(asmType)) {
if (index >= 0 && isIntPrimitive(asmType)) {
v.iinc(index, increment);
return StackValue.local(index, asmType);
}
......
......@@ -44,6 +44,12 @@ public class FunctionCodegen {
}
public void gen(JetFunction f, OwnerKind kind) {
Method method = typeMapper.mapSignature(f);
List<ValueParameterDescriptor> paramDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters();
generateMethod(f, kind, method, paramDescrs);
}
public void generateMethod(JetDeclarationWithBody f, OwnerKind kind, Method jvmSignature, List<ValueParameterDescriptor> paramDescrs) {
int flags = Opcodes.ACC_PUBLIC; // TODO.
boolean isStatic = kind == OwnerKind.NAMESPACE;
......@@ -53,8 +59,7 @@ public class FunctionCodegen {
boolean isAbstract = kind == OwnerKind.INTERFACE || bodyExpression == null;
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
Method method = typeMapper.mapSignature(f);
final MethodVisitor mv = v.visitMethod(flags, method.getName(), method.getDescriptor(), null, null);
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if (kind != OwnerKind.INTERFACE) {
mv.visitCode();
FrameMap frameMap = new FrameMap();
......@@ -63,15 +68,13 @@ public class FunctionCodegen {
frameMap.enterTemp(); // 0 slot for this
}
List<ValueParameterDescriptor> parameDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters();
Type[] argTypes = method.getArgumentTypes();
for (int i = 0; i < parameDescrs.size(); i++) {
ValueParameterDescriptor parameter = parameDescrs.get(i);
Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
frameMap.enter(parameter, argTypes[i].getSize());
}
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, method.getReturnType());
ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, jvmSignature.getReturnType());
bodyExpression.accept(codegen);
generateReturn(mv, bodyExpression, codegen);
mv.visitMaxs(0, 0);
......
......@@ -2,7 +2,9 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.psi.JetNamespace;
import org.jetbrains.jet.lang.psi.JetParameter;
import org.jetbrains.jet.lang.psi.JetTypeReference;
import org.jetbrains.jet.lang.resolve.BindingContext;
......@@ -32,6 +34,10 @@ public class JetTypeMapper {
return Type.getType("L" + jvmName(psiClass) + ";");
}
static String jvmName(JetNamespace namespace) {
return NamespaceCodegen.getJVMClassName(namespace.getFQName());
}
public Type mapType(final JetType jetType) {
if (jetType.equals(JetStandardClasses.getUnitType())) {
return Type.VOID_TYPE;
......@@ -130,4 +136,22 @@ public class JetTypeMapper {
}
return new Method(f.getName(), returnType, parameterTypes);
}
@Nullable
public Method mapGetterSignature(PropertyDescriptor descriptor) {
if (descriptor.getGetter() == null) {
return null;
}
Type returnType = mapType(descriptor.getOutType());
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]);
}
@Nullable
public Method mapSetterSignature(PropertyDescriptor descriptor) {
if (descriptor.getSetter() == null) {
return null;
}
Type paramType = mapType(descriptor.getInType());
return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType });
}
}
......@@ -35,8 +35,9 @@ public class NamespaceCodegen {
public void generate(JetNamespace namespace) {
BindingContext bindingContext = AnalyzingUtils.analyzeNamespace(namespace, ErrorHandler.THROW_EXCEPTION);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, JetStandardLibrary.getJetStandardLibrary(project), bindingContext);
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext);
final PropertyCodegen propertyCodegen = new PropertyCodegen(v, standardLibrary, bindingContext, functionCodegen);
final ClassCodegen classCodegen = codegens.forClass(bindingContext);
for (JetDeclaration declaration : namespace.getDeclarations()) {
......
package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.jet.lang.psi.JetConstantExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Collections;
/**
* @author max
*/
public class PropertyCodegen {
private final BindingContext context;
private final FunctionCodegen functionCodegen;
private final ClassVisitor v;
private final JetTypeMapper mapper;
public PropertyCodegen(ClassVisitor v) {
public PropertyCodegen(ClassVisitor v, JetStandardLibrary standardLibrary, BindingContext context, FunctionCodegen functionCodegen) {
this.v = v;
this.context = context;
this.functionCodegen = functionCodegen;
this.mapper = new JetTypeMapper(standardLibrary, context);
}
public void genInNamespace(JetProperty p) {
......@@ -30,6 +45,45 @@ public class PropertyCodegen {
}
public void gen(JetProperty p, OwnerKind kind) {
if (kind == OwnerKind.NAMESPACE) {
final VariableDescriptor descriptor = context.getVariableDescriptor(p);
if (!(descriptor instanceof PropertyDescriptor)) {
throw new UnsupportedOperationException("expect a property to have a property descriptor");
}
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (context.hasBackingField(propertyDescriptor)) {
Object value = null;
final JetExpression initializer = p.getInitializer();
if (initializer != null) {
if (initializer instanceof JetConstantExpression) {
value = ((JetConstantExpression) initializer).getValue();
}
}
v.visitField(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE,
p.getName(),
mapper.mapType(descriptor.getOutType()).getDescriptor(),
null, value);
}
final JetPropertyAccessor getter = p.getGetter();
if (getter != null) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
Collections.<ValueParameterDescriptor>emptyList());
}
final JetPropertyAccessor setter = p.getSetter();
if (setter != null) {
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
assert setterDescriptor != null;
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor),
setterDescriptor.getUnsubstitutedValueParameters());
}
}
}
public static String getterName(String propertyName) {
return "get" + StringUtil.capitalizeWithJavaBeanConvention(propertyName);
}
public static String setterName(String propertyName) {
return "set" + StringUtil.capitalizeWithJavaBeanConvention(propertyName);
}
}
......@@ -6,6 +6,7 @@ import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import org.objectweb.asm.commons.Method;
/**
* @author yole
......@@ -70,6 +71,10 @@ public abstract class StackValue {
return new Field(type, owner, name, isStatic);
}
public static StackValue property(String name, String owner, Type type, Method getter, Method setter) {
return new Property(name, owner, getter, setter, type);
}
private static void box(final Type type, InstructionAdapter v) {
if (type == Type.INT_TYPE) {
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
......@@ -368,4 +373,39 @@ public abstract class StackValue {
v.visitFieldInsn(isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD, owner, name, this.type.getDescriptor());
}
}
private static class Property extends StackValue {
private final String name;
private final String owner;
private final Method getter;
private final Method setter;
public Property(String name, String owner, Method getter, Method setter, Type type) {
super(type);
this.name = name;
this.owner = owner;
this.getter = getter;
this.setter = setter;
}
@Override
public void put(Type type, InstructionAdapter v) {
if (getter == null) {
v.visitFieldInsn(Opcodes.GETSTATIC, owner, name, type.getDescriptor());
}
else {
v.invokestatic(owner, getter.getName(), getter.getDescriptor());
}
}
@Override
public void store(InstructionAdapter v) {
if (setter == null) {
v.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, type.getDescriptor());
}
else {
v.invokestatic(owner, setter.getName(), setter.getDescriptor());
}
}
}
}
private var x = 0;
fun increment(): Int {
return ++x;
}
var collector: String = ""
set(it) { $collector = $collector + it }
fun append(s: String): String {
collector = s;
return collector;
}
......@@ -42,7 +42,7 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
return answer.toString();
}
private Class generateNamespaceClass() {
protected Class generateNamespaceClass() {
JetFile jetFile = (JetFile) myFixture.getFile();
final JetNamespace namespace = jetFile.getRootNamespace();
String fqName = NamespaceCodegen.getJVMClassName(namespace.getFQName()).replace("/", ".");
......@@ -89,6 +89,11 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
throw new IllegalArgumentException("couldn't find method " + name);
}
protected void assertIsCurrentTime(long returnValue) {
long currentTime = System.currentTimeMillis();
assertTrue(Math.abs(returnValue - currentTime) <= 1L);
}
private static class MyClassLoader extends ClassLoader {
public MyClassLoader(ClassLoader parent) {
super(parent);
......
......@@ -56,8 +56,7 @@ public class NamespaceGenTest extends CodegenTestCase {
System.out.println(generateToText());
final Method main = generateFunction();
final long returnValue = (Long) main.invoke(null);
long currentTime = System.currentTimeMillis();
assertTrue(Math.abs(returnValue - currentTime) <= 1L);
assertIsCurrentTime(returnValue);
}
public void testIdentityHashCode() throws Exception {
......
package org.jetbrains.jet.codegen;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* @author yole
*/
......@@ -8,6 +12,39 @@ public class PropertyGenTest extends CodegenTestCase {
loadFile("privateVal.jet");
System.out.println(generateToText());
// TODO
}
public void testPropertyInNamespace() throws Exception {
loadText("private val x = 239");
final Class nsClass = generateNamespaceClass();
final Field[] fields = nsClass.getDeclaredFields();
assertEquals(1, fields.length);
final Field field = fields[0];
field.setAccessible(true);
assertEquals("x", field.getName());
assertEquals(Modifier.PRIVATE | Modifier.STATIC, field.getModifiers());
assertEquals(239, field.get(null));
}
public void testFieldPropertyAccess() throws Exception {
loadFile("fieldPropertyAccess.jet");
final Method method = generateFunction();
assertEquals(1, method.invoke(null));
assertEquals(2, method.invoke(null));
}
public void testFieldGetter() throws Exception {
loadText("val now: Long get() = System.currentTimeMillis(); fun foo() = now");
final Method method = generateFunction("foo");
assertIsCurrentTime((Long) method.invoke(null));
}
public void testFieldSetter() throws Exception {
loadFile("fieldSetter.jet");
System.out.println(generateToText());
final Method method = generateFunction("append");
method.invoke(null, "IntelliJ ");
String value = (String) method.invoke(null, "IDEA");
assertEquals(value, "IntelliJ IDEA");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册