script: make top level declarations class members

This commit is contained in:
Stepan Koltsov
2012-06-05 22:56:26 +04:00
parent 877ecf83ad
commit f27147f752
21 changed files with 308 additions and 33 deletions
@@ -42,7 +42,7 @@ public class ClosureAnnotator {
private final Map<JetElement, JvmClassName> classNamesForAnonymousClasses = new HashMap<JetElement, JvmClassName>();
private final Map<ClassDescriptor, JvmClassName> classNamesForClassDescriptor = new HashMap<ClassDescriptor, JvmClassName>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final Map<FunctionDescriptor, ClassDescriptorImpl> classesForFunctions = new HashMap<FunctionDescriptor, ClassDescriptorImpl>();
private final Map<DeclarationDescriptor, ClassDescriptorImpl> classesForFunctions = new HashMap<DeclarationDescriptor, ClassDescriptorImpl>();
private final Map<DeclarationDescriptor,ClassDescriptor> enclosing = new HashMap<DeclarationDescriptor, ClassDescriptor>();
private final MultiMap<FqName, JetFile> namespaceName2Files = MultiMap.create();
@@ -86,6 +86,27 @@ public class ClosureAnnotator {
return classDescriptor;
}
@NotNull
public ClassDescriptor classDescriptorForScrpitDescriptor(@NotNull ScriptDescriptor scriptDescriptor) {
ClassDescriptorImpl classDescriptor = classesForFunctions.get(scriptDescriptor);
if (classDescriptor == null) {
classDescriptor = new ClassDescriptorImpl(
scriptDescriptor,
Collections.<AnnotationDescriptor>emptyList(),
Name.special("<script>"));
recordName(classDescriptor, JvmClassName.byInternalName("Script"));
classDescriptor.initialize(
false,
Collections.<TypeParameterDescriptor>emptyList(),
Collections.singletonList(JetStandardClasses.getAnyType()),
JetScope.EMPTY,
Collections.<ConstructorDescriptor>emptySet(),
null);
classesForFunctions.put(scriptDescriptor, classDescriptor);
}
return classDescriptor;
}
private void mapFilesToNamespaces(Collection<JetFile> files) {
for (JetFile file : files) {
if (file.isScript()) {
@@ -129,8 +129,8 @@ public abstract class CodegenContext {
return new CodegenContexts.ConstructorContext(descriptor, getContextKind(), this, typeMapper);
}
public CodegenContext intoScript(ScriptDescriptor script) {
return new CodegenContexts.ScriptContext(script, OwnerKind.IMPLEMENTATION, this, closure);
public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) {
return new CodegenContexts.ScriptContext(classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
}
public CodegenContexts.ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, JvmClassName internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) {
@@ -165,22 +165,27 @@ public class CodegenContexts {
public static class ScriptContext extends CodegenContext {
@NotNull
private final ClassDescriptor classDescriptor;
public ScriptContext(
@NotNull DeclarationDescriptor contextDescriptor,
@NotNull ClassDescriptor contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable ObjectOrClosureCodegen closureCodegen) {
super(contextDescriptor, contextKind, parentContext, closureCodegen);
this.classDescriptor = contextDescriptor;
}
@Override
protected ClassDescriptor getThisDescriptor() {
return null;
return classDescriptor;
}
@Override
public boolean isStatic() {
throw new IllegalStateException();
return true;
}
}
@@ -39,6 +39,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ScriptReceiver;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lexer.JetTokens;
@@ -741,6 +742,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) {
assert data == StackValue.none();
if (function.isScriptDeclaration()) {
return StackValue.none();
}
StackValue closure = genClosure(function);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
int index = myFrameMap.getIndex(descriptor);
@@ -844,7 +850,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.mark(blockStart);
for (JetElement statement : statements) {
if (statement instanceof JetNamedDeclaration) {
JetNamedDeclaration declaration = (JetNamedDeclaration) statement;
if (declaration.isScriptDeclaration()) {
continue;
}
}
if (statement instanceof JetProperty) {
JetProperty property = (JetProperty) statement;
final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, statement);
assert variableDescriptor != null;
@@ -877,6 +891,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
v.mark(blockEnd);
for (JetElement statement : Lists.reverse(statements)) {
if (statement instanceof JetNamedDeclaration) {
JetNamedDeclaration declaration = (JetNamedDeclaration) statement;
if (declaration.isScriptDeclaration()) {
continue;
}
}
if(statement instanceof JetNamedFunction) {
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement);
myFrameMap.leave(descriptor);
@@ -884,6 +905,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (statement instanceof JetProperty) {
JetProperty var = (JetProperty) statement;
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
assert variableDescriptor != null;
@@ -1367,8 +1389,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private boolean isCallAsFunctionObject(FunctionDescriptor fd) {
return fd instanceof ExpressionAsFunctionDescriptor
|| (fd instanceof SimpleFunctionDescriptor && (fd.getContainingDeclaration() instanceof FunctionDescriptor || fd.getContainingDeclaration() instanceof ScriptDescriptor));
if (fd.getContainingDeclaration() instanceof ScriptDescriptor) {
JetNamedFunction psi = (JetNamedFunction) BindingContextUtils.descriptorToDeclaration(bindingContext, fd);
return !psi.isScriptDeclaration();
}
else if (fd instanceof ExpressionAsFunctionDescriptor) {
return true;
}
else if (fd instanceof SimpleFunctionDescriptor && (fd.getContainingDeclaration() instanceof FunctionDescriptor || fd.getContainingDeclaration() instanceof ScriptDescriptor)) {
return true;
}
else {
return false;
}
}
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) {
@@ -1421,6 +1454,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if(type != null)
StackValue.onStack(exprType).put(type, v);
}
else if (descriptor instanceof ScriptReceiver) {
ScriptReceiver scriptReceiver = (ScriptReceiver) descriptor;
ScriptDescriptor script = (ScriptDescriptor) scriptReceiver.getDeclarationDescriptor();
ClassDescriptor classDescriptorForScript = state.getInjector().getClosureAnnotator().classDescriptorForScrpitDescriptor(script);
generateThisOrOuter(classDescriptorForScript);
}
else if(descriptor instanceof ExtensionReceiver) {
Type exprType = asmType(descriptor.getType());
ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
@@ -2283,17 +2322,30 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitProperty(JetProperty property, StackValue receiver) {
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
int index = lookupLocal(variableDescriptor);
if (index < 0) {
throw new IllegalStateException("Local variable not found for " + variableDescriptor);
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
Type sharedVarType = null;
int index = -1;
if (property.isScriptDeclaration()) {
StackValue field = StackValue.field(typeMapper.mapType(variableDescriptor.getType(), MapTypeMode.VALUE), JvmClassName.byInternalName("Script"), property.getName(), false);
return StackValue.none();
}
else {
index = lookupLocal(variableDescriptor);
if (index < 0) {
throw new IllegalStateException("Local variable not found for " + variableDescriptor);
}
sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
assert variableDescriptor != null;
}
final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
assert variableDescriptor != null;
Type varType = asmType(variableDescriptor.getType());
if(sharedVarType != null) {
if (sharedVarType != null) {
v.anew(sharedVarType);
v.dup();
v.invokespecial(sharedVarType.getInternalName(), "<init>", "()V");
@@ -2302,7 +2354,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetExpression initializer = property.getInitializer();
if (initializer != null) {
if(sharedVarType == null) {
if (property.isScriptDeclaration()) {
gen(initializer, varType);
v.putfield("Script", property.getName(), varType.getDescriptor());
}
else if (sharedVarType == null) {
gen(initializer, varType);
v.store(index, varType);
}
@@ -699,7 +699,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
curParam++;
}
generateInitializers(codegen, iv);
generateInitializers(codegen, iv, myClass.getDeclarations(), bindingContext, typeMapper);
generateTraitMethods(codegen);
@@ -915,8 +915,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
protected void generateInitializers(ExpressionCodegen codegen, InstructionAdapter iv) {
for (JetDeclaration declaration : myClass.getDeclarations()) {
public static void generateInitializers(@NotNull ExpressionCodegen codegen, @NotNull InstructionAdapter iv, @NotNull List<JetDeclaration> declarations,
@NotNull BindingContext bindingContext, @NotNull JetTypeMapper typeMapper) {
for (JetDeclaration declaration : declarations) {
if (declaration instanceof JetProperty) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.get(BindingContext.VARIABLE, declaration);
if (bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
@@ -167,6 +167,9 @@ public class JetTypeMapper {
}
return JvmClassName.byType(asmType);
}
else if (containingDeclaration instanceof ScriptDescriptor) {
return JvmClassName.byInternalName("Script");
}
else {
throw new UnsupportedOperationException("don't know how to generate owner for parent " + containingDeclaration);
}
@@ -578,6 +581,10 @@ public class JetTypeMapper {
invokeOpcode = INVOKESPECIAL;
thisClass = null;
}
else if (functionParent instanceof ScriptDescriptor) {
thisClass = owner = ownerForDefaultParam = ownerForDefaultImpl = JvmClassName.byInternalName("Script");
invokeOpcode = INVOKEVIRTUAL;
}
else if (functionParent instanceof ClassDescriptor) {
FunctionDescriptor declarationFunctionDescriptor = findAnyDeclaration(functionDescriptor);
@@ -18,9 +18,12 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JdkNames;
import org.objectweb.asm.MethodVisitor;
@@ -43,6 +46,12 @@ public class ScriptCodegen {
private ClassFileFactory classFileFactory;
@NotNull
private JetTypeMapper jetTypeMapper;
@NotNull
private MemberCodegen memberCodegen;
@NotNull
private ClosureAnnotator closureAnnotator;
@NotNull
private BindingContext bindingContext;
@Inject
@@ -60,13 +69,30 @@ public class ScriptCodegen {
this.jetTypeMapper = jetTypeMapper;
}
@Inject
public void setMemberCodegen(@NotNull MemberCodegen memberCodegen) {
this.memberCodegen = memberCodegen;
}
@Inject
public void setClosureAnnotator(@NotNull ClosureAnnotator closureAnnotator) {
this.closureAnnotator = closureAnnotator;
}
@Inject
public void setBindingContext(@NotNull BindingContext bindingContext) {
this.bindingContext = bindingContext;
}
public void generate(JetScript scriptDeclaration) {
ScriptDescriptor scriptDescriptor = (ScriptDescriptor) state.getBindingContext().get(BindingContext.SCRIPT, scriptDeclaration);
CodegenContext context = CodegenContexts.STATIC.intoScript(scriptDescriptor);
ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScrpitDescriptor(scriptDescriptor);
CodegenContexts.ScriptContext context = (CodegenContexts.ScriptContext) CodegenContexts.STATIC.intoScript(scriptDescriptor, classDescriptorForScript);
ClassBuilder classBuilder = classFileFactory.newVisitor("Script.class");
classBuilder.defineClass(scriptDeclaration,
@@ -77,13 +103,17 @@ public class ScriptCodegen {
JdkNames.JL_OBJECT.getInternalName(),
new String[0]);
genConstructor(scriptDeclaration, scriptDescriptor, classBuilder, context);
genMembers(scriptDeclaration, context, classBuilder);
genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder, context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()));
classBuilder.done();
}
private void genConstructor(
@NotNull JetScript scriptDeclaration, @NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassBuilder classBuilder, @NotNull CodegenContext outerContext) {
@NotNull JetScript scriptDeclaration,
@NotNull ScriptDescriptor scriptDescriptor,
@NotNull ClassDescriptor classDescriptorForScript,
@NotNull ClassBuilder classBuilder, @NotNull CodegenContext context) {
Type blockType = jetTypeMapper.mapType(scriptDescriptor.getReturnType(), MapTypeMode.VALUE);
@@ -105,8 +135,6 @@ public class ScriptCodegen {
instructionAdapter.load(0, Type.getObjectType("Script"));
CodegenContext context = outerContext.intoScript(scriptDescriptor);
FrameMap frameMap = context.prepareFrame(jetTypeMapper);
Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes();
@@ -117,6 +145,12 @@ public class ScriptCodegen {
frameMap.enter(parameter, argTypes[i+add].getSize());
}
ImplementationBodyCodegen.generateInitializers(
new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state),
instructionAdapter,
scriptDeclaration.getDeclarations(),
bindingContext,
jetTypeMapper);
StackValue stackValue = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state).gen(scriptDeclaration.getBlockExpression());
if (stackValue.type != Type.VOID_TYPE) {
@@ -128,4 +162,10 @@ public class ScriptCodegen {
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
private void genMembers(@NotNull JetScript scriptDeclaration, @NotNull CodegenContext context, @NotNull ClassBuilder classBuilder) {
for (JetDeclaration decl : scriptDeclaration.getDeclarations()) {
memberCodegen.generateFunctionOrProperty((JetTypeParameterListOwner) decl, context, classBuilder);
}
}
}
@@ -99,8 +99,11 @@ public class InjectorForJvmCodegen {
this.classCodegen.setJetTypeMapper(jetTypeMapper);
this.classCodegen.setState(generationState);
this.scriptCodegen.setBindingContext(bindingContext);
this.scriptCodegen.setClassFileFactory(classFileFactory);
this.scriptCodegen.setClosureAnnotator(closureAnnotator);
this.scriptCodegen.setJetTypeMapper(jetTypeMapper);
this.scriptCodegen.setMemberCodegen(memberCodegen);
this.scriptCodegen.setState(generationState);
this.intrinsics.setMyProject(project);
@@ -111,8 +114,8 @@ public class InjectorForJvmCodegen {
this.memberCodegen.setState(generationState);
closureAnnotator.setBindingContext(bindingContext);
closureAnnotator.setFiles(listOfJetFile);
this.closureAnnotator.setBindingContext(bindingContext);
this.closureAnnotator.setFiles(listOfJetFile);
jetTypeMapper.init();
@@ -158,4 +161,8 @@ public class InjectorForJvmCodegen {
return this.memberCodegen;
}
public ClosureAnnotator getClosureAnnotator() {
return this.closureAnnotator;
}
}