diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index d3ee9971ca5..9cd187bf1b9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -134,7 +134,7 @@ public abstract class CodegenContext { } public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) { - return new CodegenContexts.ScriptContext(classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); + return new CodegenContexts.ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); } public CodegenContexts.ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, JvmClassName internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java index 5250cbbbc73..be236fcca97 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; +import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -111,8 +112,17 @@ public class CodegenContexts { } public static class MethodContext extends ReceiverContext { - public MethodContext(FunctionDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext) { + @NotNull + private final FunctionDescriptor functionDescriptor; + + public MethodContext(@NotNull FunctionDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext) { super(contextType instanceof PropertyAccessorDescriptor ? ((PropertyAccessorDescriptor)contextType).getCorrespondingProperty() : contextType, contextKind, parentContext, null); + this.functionDescriptor = contextType; + } + + @NotNull + public FunctionDescriptor getFunctionDescriptor() { + return functionDescriptor; } @Override @@ -167,8 +177,11 @@ public class CodegenContexts { @NotNull private final ClassDescriptor classDescriptor; + @NotNull + private final ScriptDescriptor scriptDescriptor; public ScriptContext( + @NotNull ScriptDescriptor scriptDescriptor, @NotNull ClassDescriptor contextDescriptor, @NotNull OwnerKind contextKind, @Nullable CodegenContext parentContext, @@ -176,6 +189,7 @@ public class CodegenContexts { super(contextDescriptor, contextKind, parentContext, closureCodegen); this.classDescriptor = contextDescriptor; + this.scriptDescriptor = scriptDescriptor; } @Override @@ -183,6 +197,11 @@ public class CodegenContexts { return classDescriptor; } + @NotNull + public ScriptDescriptor getScriptDescriptor() { + return scriptDescriptor; + } + @Override public boolean isStatic() { return true; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a12e9ba97e5..52863884599 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.tree.IElementType; +import com.sun.tools.internal.ws.wsdl.document.schema.SchemaConstants; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; @@ -1469,10 +1470,7 @@ public class ExpressionCodegen extends JetVisitor { 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); + generateScript((ScriptReceiver) descriptor); } else if(descriptor instanceof ExtensionReceiver) { Type exprType = asmType(descriptor.getType()); @@ -1520,6 +1518,44 @@ public class ExpressionCodegen extends JetVisitor { return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); } + private void generateScript(@NotNull ScriptReceiver receiver) { + CodegenContext cur = context; + + //PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(bindingContext, calleeContainingClass); + //boolean isObject = psiElement instanceof JetClassOrObject && CodegenUtil.isNonLiteralObject((JetClassOrObject) psiElement); + + cur = context; + StackValue result = StackValue.local(0, TYPE_OBJECT); + while (cur != null) { + if(cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) + cur = cur.getParentContext(); + + if (cur instanceof CodegenContexts.ScriptContext) { + CodegenContexts.ScriptContext scriptContext = (CodegenContexts.ScriptContext) cur; + + JvmClassName currentScriptClassName = state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptContext.getScriptDescriptor()); + if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) { + result.put(currentScriptClassName.getAsmType(), v); + } + else { + JvmClassName className = state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(receiver.getDeclarationDescriptor()); + String fieldName = state.getInjector().getScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor()); + result.put(currentScriptClassName.getAsmType(), v); + StackValue.field(className.getAsmType(), currentScriptClassName, fieldName, false).put(className.getAsmType(), v); + } + return; + } + + result = cur.getOuterExpression(result); + + if(cur instanceof CodegenContexts.ConstructorContext) { + cur = cur.getParentContext(); + } + cur = cur.getParentContext(); + } + + throw new UnsupportedOperationException(); } + public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) { CodegenContext cur = context; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 9043959432e..6bba71c3690 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -30,6 +30,7 @@ import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.di.InjectorForJvmCodegen; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; +import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -40,6 +41,7 @@ import org.jetbrains.jet.utils.Progress; import org.objectweb.asm.commons.Method; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -145,6 +147,8 @@ public class GenerationState { } } + injector.getScriptCodegen().registerEarlierScripts(Collections.>emptyList()); + MultiMap namespaceGrouping = new MultiMap(); for (JetFile file : this.files) { if (file == null) throw new IllegalArgumentException("A null file given for compilation"); @@ -156,6 +160,24 @@ public class GenerationState { } } + public void compileScript( + @NotNull JetScript script, + @NotNull JvmClassName className, + @NotNull List> earlierScripts, + @NotNull CompilationErrorHandler errorHandler) { + poison(); + + injector.getScriptCodegen().registerEarlierScripts(earlierScripts); + + injector.getClosureAnnotator().registerClassNameForScript(script, className); + + generateNamespace( + JetPsiUtil.getFQName((JetFile) script.getContainingFile()), + Collections.singleton((JetFile) script.getContainingFile()), + errorHandler, + progress); + } + protected void generateNamespace(FqName fqName, Collection namespace, CompilationErrorHandler errorHandler, Progress progress) { NamespaceCodegen codegen = forNamespace(fqName, namespace); codegen.generate(errorHandler, progress); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index a266e41e5d9..e25fed6f397 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -899,13 +899,19 @@ public class JetTypeMapper { } @NotNull - public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script) { + public JvmMethodSignature mapScriptSignature(@NotNull ScriptDescriptor script, @NotNull List importedScripts) { BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); writeFormalTypeParameters(Collections.emptyList(), signatureWriter); signatureWriter.writeParametersStart(); + for (ScriptDescriptor importedScript : importedScripts) { + signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); + mapType(closureAnnotator.classDescriptorForScrpitDescriptor(importedScript).getDefaultType(), signatureWriter, MapTypeMode.VALUE); + signatureWriter.writeParameterTypeEnd(); + } + for (ValueParameterDescriptor valueParameter : script.getValueParameters()) { signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); mapType(valueParameter.getType(), signatureWriter, MapTypeMode.VALUE); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java index 7e770c23d6b..22cd6a33882 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java @@ -16,6 +16,8 @@ package org.jetbrains.jet.codegen; +import com.google.common.collect.Lists; +import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -33,6 +35,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import javax.inject.Inject; +import java.util.Collections; +import java.util.List; /** * @author Stepan Koltsov @@ -56,6 +60,8 @@ public class ScriptCodegen { @NotNull private BindingContext bindingContext; + private List earlierScripts; + @Inject public void setState(@NotNull GenerationState state) { @@ -110,7 +116,8 @@ public class ScriptCodegen { genMembers(scriptDeclaration, context, classBuilder); genFieldsForParameters(scriptDescriptor, classBuilder); - genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder, context.intoFunction(scriptDescriptor.getScriptCodeDescriptor())); + genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder, + context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()), earlierScripts); classBuilder.done(); } @@ -119,13 +126,15 @@ public class ScriptCodegen { @NotNull JetScript scriptDeclaration, @NotNull ScriptDescriptor scriptDescriptor, @NotNull ClassDescriptor classDescriptorForScript, - @NotNull ClassBuilder classBuilder, @NotNull CodegenContext context) { + @NotNull ClassBuilder classBuilder, + @NotNull CodegenContext context, + @NotNull List importedScripts) { Type blockType = jetTypeMapper.mapType(scriptDescriptor.getReturnType(), MapTypeMode.VALUE); classBuilder.newField(null, Opcodes.ACC_PUBLIC, LAST_EXPRESSION_VALUE_FIELD_NAME, blockType.getDescriptor(), null, null); - JvmMethodSignature jvmSignature = jetTypeMapper.mapScriptSignature(scriptDescriptor); + JvmMethodSignature jvmSignature = jetTypeMapper.mapScriptSignature(scriptDescriptor, importedScripts); state.setScriptConstructorMethod(jvmSignature.getAsmMethod()); @@ -145,6 +154,10 @@ public class ScriptCodegen { FrameMap frameMap = context.prepareFrame(jetTypeMapper); + for (ScriptDescriptor importedScript : importedScripts) { + frameMap.enter(importedScript, 1); + } + Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes(); int add = 0; @@ -161,6 +174,15 @@ public class ScriptCodegen { jetTypeMapper); int offset = 1; + + for (ScriptDescriptor earlierScript : importedScripts) { + JvmClassName earlierClassName = closureAnnotator.classNameForScriptDescriptor(earlierScript); + instructionAdapter.load(0, className.getAsmType()); + instructionAdapter.load(offset, earlierClassName.getAsmType()); + offset += earlierClassName.getAsmType().getSize(); + instructionAdapter.putfield(className.getInternalName(), getScriptFieldName(earlierScript), earlierClassName.getAsmType().getDescriptor()); + } + for (ValueParameterDescriptor parameter : scriptDescriptor.getValueParameters()) { Type parameterType = jetTypeMapper.mapType(parameter.getType(), MapTypeMode.VALUE); instructionAdapter.load(0, className.getAsmType()); @@ -181,6 +203,12 @@ public class ScriptCodegen { } private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) { + for (ScriptDescriptor earlierScript : earlierScripts) { + JvmClassName earlierClassName = closureAnnotator.classNameForScriptDescriptor(earlierScript); + int access = Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL; + classBuilder.newField(null, access, getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null); + } + for (ValueParameterDescriptor parameter : script.getValueParameters()) { Type parameterType = jetTypeMapper.mapType(parameter.getType(), MapTypeMode.VALUE); int access = Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL; @@ -193,4 +221,33 @@ public class ScriptCodegen { memberCodegen.generateFunctionOrProperty((JetTypeParameterListOwner) decl, context, classBuilder); } } + + public void registerEarlierScripts(List> earlierScripts) { + for (Pair t : earlierScripts) { + ScriptDescriptor earlierDescriptor = t.first; + JvmClassName earlierClassName = t.second; + + closureAnnotator.registerClassNameForScript(earlierDescriptor, earlierClassName); + } + + List earlierScriptDescriptors = Lists.newArrayList(); + for (Pair t : earlierScripts) { + ScriptDescriptor earlierDescriptor = t.first; + JvmClassName earlierClassName = t.second; + earlierScriptDescriptors.add(earlierDescriptor); + } + this.earlierScripts = earlierScriptDescriptors; + } + + public int getScriptIndex(@NotNull ScriptDescriptor scriptDescriptor) { + int index = earlierScripts.indexOf(scriptDescriptor); + if (index < 0) { + throw new IllegalStateException("Unregistered script: " + scriptDescriptor); + } + return index + 1; + } + + public String getScriptFieldName(@NotNull ScriptDescriptor scriptDescriptor) { + return "script$" + getScriptIndex(scriptDescriptor); + } } diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/EarlierLine.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/EarlierLine.java new file mode 100644 index 00000000000..84a0e885339 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/EarlierLine.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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.jetbrains.jet.cli.jvm.repl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; + +/** + * @author Stepan Koltsov + */ +public class EarlierLine { + @NotNull + private final String code; + @NotNull + private final ScriptDescriptor scriptDescriptor; + @NotNull + private final Class scriptClass; + @NotNull + private final Object scriptInstance; + @NotNull + private final JvmClassName className; + + public EarlierLine(@NotNull String code, @NotNull ScriptDescriptor scriptDescriptor, @NotNull Class scriptClass, @NotNull Object scriptInstance, @NotNull JvmClassName className) { + this.code = code; + this.scriptDescriptor = scriptDescriptor; + this.scriptClass = scriptClass; + this.scriptInstance = scriptInstance; + this.className = className; + } + + @NotNull + public String getCode() { + return code; + } + + @NotNull + public ScriptDescriptor getScriptDescriptor() { + return scriptDescriptor; + } + + @NotNull + public Class getScriptClass() { + return scriptClass; + } + + @NotNull + public Object getScriptInstance() { + return scriptInstance; + } + + @NotNull + public JvmClassName getClassName() { + return className; + } +} diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplClassLoader.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplClassLoader.java new file mode 100644 index 00000000000..7f8a9a88971 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplClassLoader.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * 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.jetbrains.jet.cli.jvm.repl; + +import com.google.common.collect.Maps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.PrintWriter; +import java.util.Map; + +/** + * @author Stepan Koltsov + */ +public class ReplClassLoader extends ClassLoader { + + private Map classes = Maps.newLinkedHashMap(); + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classBytes = classes.get(JvmClassName.byFqNameWithoutInnerClasses(name)); + if (classBytes != null) { + return defineClass(name, classBytes, 0, classBytes.length); + } + else { + return super.findClass(name); + } + } + + public void addClass(@NotNull JvmClassName className, @NotNull byte[] bytes) { + byte[] oldBytes = classes.put(className, bytes); + if (oldBytes != null) { + throw new IllegalStateException("Rewrite at key " + className); + } + } + + public void dumpClasses(@NotNull PrintWriter writer) { + for (byte[] classBytes : classes.values()) { + new ClassReader(classBytes).accept(new TraceClassVisitor(writer), 0); + } + } + +} diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java index 1399567cdfc..145fbd2588d 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java @@ -17,44 +17,52 @@ package org.jetbrains.jet.cli.jvm.repl; import com.google.common.base.Predicates; +import com.google.common.collect.Lists; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.PsiFileFactoryImpl; import com.intellij.testFramework.LightVirtualFile; -import com.intellij.util.ExceptionUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; -import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.codegen.ClassBuilderFactories; import org.jetbrains.jet.codegen.CompilationErrorHandler; -import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.codegen.GenerationState; -import org.jetbrains.jet.codegen.ScriptCodegen; import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.NamespaceLikeBuilderDummy; +import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; -import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; +import org.jetbrains.jet.lang.resolve.TraceBasedRedeclarationHandler; import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; +import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.utils.ExceptionUtils; import org.jetbrains.jet.utils.Progress; +import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Collections; +import java.util.List; /** * @author Stepan Koltsov @@ -62,6 +70,10 @@ import java.util.Collections; public class ReplInterpreter { private int lineNumber = 0; + @Nullable + private JetScope lastLineScope; + private List earlierLines = Lists.newArrayList(); + private final ReplClassLoader classLoader = new ReplClassLoader(); @NotNull private final InjectorForTopDownAnalyzerForJvm injector; @@ -69,12 +81,14 @@ public class ReplInterpreter { private final JetCoreEnvironment jetCoreEnvironment; @NotNull private final BindingTraceContext trace; + @NotNull + private final ModuleDescriptor module; public ReplInterpreter(@NotNull Disposable disposable, @NotNull CompilerDependencies compilerDependencies) { jetCoreEnvironment = new JetCoreEnvironment(disposable, compilerDependencies); Project project = jetCoreEnvironment.getProject(); trace = new BindingTraceContext(); - ModuleDescriptor module = new ModuleDescriptor(Name.special("")); + module = new ModuleDescriptor(Name.special("")); TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters( Predicates.alwaysTrue(), false, @@ -86,6 +100,8 @@ public class ReplInterpreter { public Object eval(@NotNull String line) { ++lineNumber; + JvmClassName scriptClassName = JvmClassName.byInternalName("Line" + lineNumber); + LightVirtualFile virtualFile = new LightVirtualFile("line" + lineNumber + ".ktscript", JetLanguage.INSTANCE, line); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())).trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); @@ -94,9 +110,7 @@ public class ReplInterpreter { injector.getTopDownAnalyzer().prepareForTheNextReplLine(); - injector.getTopDownAnalyzer().analyzeFiles(Collections.singletonList(psiFile), Collections.emptyList()); - - AnalyzingUtils.throwExceptionOnErrors(trace.getBindingContext()); + ScriptDescriptor scriptDescriptor = doAnalyze(psiFile); Progress backendProgress = new Progress() { @Override @@ -104,22 +118,85 @@ public class ReplInterpreter { } }; + List> earierScripts = Lists.newArrayList(); + + for (EarlierLine earlierLine : earlierLines) { + earierScripts.add(Pair.create(earlierLine.getScriptDescriptor(), earlierLine.getClassName())); + } + GenerationState generationState = new GenerationState(jetCoreEnvironment.getProject(), ClassBuilderFactories.binaries(false), backendProgress, AnalyzeExhaust.success(trace.getBindingContext(), JetStandardLibrary.getInstance()), Collections.singletonList(psiFile), jetCoreEnvironment.getCompilerDependencies().getCompilerSpecialMode()); - generationState.compileCorrectFiles(CompilationErrorHandler.THROW_EXCEPTION); + generationState.compileScript(psiFile.getScript(), scriptClassName, earierScripts, CompilationErrorHandler.THROW_EXCEPTION); + + for (String file : generationState.getFactory().files()) { + classLoader.addClass(JvmClassName.byInternalName(file.replaceFirst("\\.class$", "")), generationState.getFactory().asBytes(file)); + } try { - Class scriptClass = new GeneratedClassLoader(generationState.getFactory()).loadClass(ScriptCodegen.SCRIPT_DEFAULT_CLASS_NAME.getFqName().getFqName()); - Constructor scriptInstanceConstructor = scriptClass.getConstructor(new Class[0]); - Object scriptInstance = scriptInstanceConstructor.newInstance(new Object[0]); + Class scriptClass = classLoader.loadClass(scriptClassName.getFqName().getFqName()); + + Class[] constructorParams = new Class[earlierLines.size()]; + Object[] constructorArgs = new Object[earlierLines.size()]; + + for (int i = 0; i < earlierLines.size(); ++i) { + constructorParams[i] = earlierLines.get(i).getScriptClass(); + constructorArgs[i] = earlierLines.get(i).getScriptInstance(); + } + + Constructor scriptInstanceConstructor = scriptClass.getConstructor(constructorParams); + Object scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs); Field rvField = scriptClass.getDeclaredField("rv"); rvField.setAccessible(true); Object rv = rvField.get(scriptInstance); + + earlierLines.add(new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance, scriptClassName)); + return rv; - } catch (Exception e) { + } catch (Throwable e) { + PrintWriter writer = new PrintWriter(System.err); + classLoader.dumpClasses(writer); + writer.flush(); throw ExceptionUtils.rethrow(e); } } + private ScriptDescriptor doAnalyze(@NotNull JetFile psiFile) { + final WritableScope scope = new WritableScopeImpl( + JetScope.EMPTY, module, + new TraceBasedRedeclarationHandler(trace), "Root scope in analyzeNamespace"); + + scope.changeLockLevel(WritableScope.LockLevel.BOTH); + + NamespaceDescriptorImpl rootNs = injector.getNamespaceFactory().createNamespaceDescriptorPathIfNeeded(FqName.ROOT); + + // map "jet" namespace into JetStandardLibrary/Classes + // @see DefaultModuleConfiguraiton#extendNamespaceScope + injector.getNamespaceFactory().createNamespaceDescriptorPathIfNeeded(JetStandardClasses.STANDARD_CLASSES_FQNAME); + + // Import a scope that contains all top-level namespaces that come from dependencies + // This makes the namespaces visible at all, does not import themselves + scope.importScope(rootNs.getMemberScope()); + + if (lastLineScope != null) { + scope.importScope(lastLineScope); + } + + scope.changeLockLevel(WritableScope.LockLevel.READING); + + // dummy builder is used because "root" is module descriptor, + // namespaces added to module explicitly in + injector.getTopDownAnalyzer().doProcess(scope, new NamespaceLikeBuilderDummy(), Collections.singletonList(psiFile)); + + // TODO: print, not throw + AnalyzingUtils.throwExceptionOnErrors(trace.getBindingContext()); + + ScriptDescriptor scriptDescriptor = injector.getTopDownAnalysisContext().getScripts().get(psiFile.getScript()); + lastLineScope = trace.get(BindingContext.SCRIPT_SCOPE, scriptDescriptor); + if (lastLineScope == null) { + throw new IllegalStateException("last line scope is not initialized"); + } + + return scriptDescriptor; + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 14f1e1187b5..78dc4bc010e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -32,6 +32,7 @@ import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.PsiClassFinderForJvm; +import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; import org.jetbrains.jet.lang.resolve.DeclarationResolver; import org.jetbrains.jet.lang.resolve.AnnotationResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolver; @@ -41,7 +42,6 @@ import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; import org.jetbrains.jet.lang.resolve.ImportsResolver; import org.jetbrains.jet.lang.resolve.DelegationResolver; -import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; import org.jetbrains.jet.lang.resolve.OverloadResolver; import org.jetbrains.jet.lang.resolve.OverrideResolver; import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; @@ -74,6 +74,7 @@ public class InjectorForTopDownAnalyzerForJvm { private JavaBridgeConfiguration javaBridgeConfiguration; private JavaDescriptorResolver javaDescriptorResolver; private PsiClassFinderForJvm psiClassFinderForJvm; + private NamespaceFactoryImpl namespaceFactory; private DeclarationResolver declarationResolver; private AnnotationResolver annotationResolver; private CallResolver callResolver; @@ -83,7 +84,6 @@ public class InjectorForTopDownAnalyzerForJvm { private OverloadingConflictResolver overloadingConflictResolver; private ImportsResolver importsResolver; private DelegationResolver delegationResolver; - private NamespaceFactoryImpl namespaceFactory; private OverloadResolver overloadResolver; private OverrideResolver overrideResolver; private TypeHierarchyResolver typeHierarchyResolver; @@ -113,6 +113,7 @@ public class InjectorForTopDownAnalyzerForJvm { this.javaBridgeConfiguration = new JavaBridgeConfiguration(); this.javaDescriptorResolver = new JavaDescriptorResolver(); this.psiClassFinderForJvm = new PsiClassFinderForJvm(); + this.namespaceFactory = new NamespaceFactoryImpl(); this.declarationResolver = new DeclarationResolver(); this.annotationResolver = new AnnotationResolver(); this.callResolver = new CallResolver(); @@ -122,7 +123,6 @@ public class InjectorForTopDownAnalyzerForJvm { this.overloadingConflictResolver = new OverloadingConflictResolver(); this.importsResolver = new ImportsResolver(); this.delegationResolver = new DelegationResolver(); - this.namespaceFactory = new NamespaceFactoryImpl(); this.overloadResolver = new OverloadResolver(); this.overrideResolver = new OverrideResolver(); this.typeHierarchyResolver = new TypeHierarchyResolver(); @@ -176,6 +176,10 @@ public class InjectorForTopDownAnalyzerForJvm { psiClassFinderForJvm.setCompilerDependencies(compilerDependencies); psiClassFinderForJvm.setProject(project); + this.namespaceFactory.setConfiguration(javaBridgeConfiguration); + this.namespaceFactory.setModuleDescriptor(moduleDescriptor); + this.namespaceFactory.setTrace(bindingTrace); + declarationResolver.setAnnotationResolver(annotationResolver); declarationResolver.setContext(topDownAnalysisContext); declarationResolver.setDescriptorResolver(descriptorResolver); @@ -207,10 +211,6 @@ public class InjectorForTopDownAnalyzerForJvm { delegationResolver.setContext(topDownAnalysisContext); delegationResolver.setTrace(bindingTrace); - namespaceFactory.setConfiguration(javaBridgeConfiguration); - namespaceFactory.setModuleDescriptor(moduleDescriptor); - namespaceFactory.setTrace(bindingTrace); - overloadResolver.setContext(topDownAnalysisContext); overloadResolver.setTrace(bindingTrace); @@ -291,4 +291,8 @@ public class InjectorForTopDownAnalyzerForJvm { return this.javaBridgeConfiguration; } + public NamespaceFactoryImpl getNamespaceFactory() { + return this.namespaceFactory; + } + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 4cb0f66b05b..efe4ab7e9b0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -91,6 +91,8 @@ public interface BindingContext { WritableSlice TYPE_RESOLUTION_SCOPE = Slices.createSimpleSlice(); WritableSlice RESOLUTION_SCOPE = Slices.createSimpleSlice(); + WritableSlice SCRIPT_SCOPE = Slices.createSimpleSlice(); + /** Collected during analyze, used in IDE in auto-cast completion */ WritableSlice NON_DEFAULT_EXPRESSION_DATA_FLOW = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ScriptReceiver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ScriptReceiver.java index 8dabc3e0715..3cb869e5e2b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ScriptReceiver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ScriptReceiver.java @@ -37,7 +37,7 @@ public class ScriptReceiver implements ThisReceiverDescriptor { @NotNull @Override - public DeclarationDescriptor getDeclarationDescriptor() { + public ScriptDescriptor getDeclarationDescriptor() { return scriptDescriptor; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index 17d2fc36d6e..2c1c53a319f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -194,6 +194,11 @@ public class ExpressionTypingServices { scope.changeLockLevel(WritableScope.LockLevel.BOTH); JetType r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context, trace); scope.changeLockLevel(WritableScope.LockLevel.READING); + + if (containingDescriptor instanceof ScriptDescriptor) { + trace.record(BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope); + } + return r; } diff --git a/compiler/testData/repl/function.repl b/compiler/testData/repl/function.repl new file mode 100644 index 00000000000..5bbc5cd8e73 --- /dev/null +++ b/compiler/testData/repl/function.repl @@ -0,0 +1,4 @@ +>>> fun foo() = 2 +null +>>> foo() +2 diff --git a/compiler/testData/repl/functionReferencesPrev.repl b/compiler/testData/repl/functionReferencesPrev.repl new file mode 100644 index 00000000000..3d17ab3448e --- /dev/null +++ b/compiler/testData/repl/functionReferencesPrev.repl @@ -0,0 +1,6 @@ +>>> val x = 1 +null +>>> fun add1(y: Int) = x + y +null +>>> add1(999999) +1000000 diff --git a/compiler/tests/org/jetbrains/jet/repl/ReplInterpreterTest.java b/compiler/tests/org/jetbrains/jet/repl/ReplInterpreterTest.java index ce668d0e4d8..84426ab0553 100644 --- a/compiler/tests/org/jetbrains/jet/repl/ReplInterpreterTest.java +++ b/compiler/tests/org/jetbrains/jet/repl/ReplInterpreterTest.java @@ -76,4 +76,15 @@ public class ReplInterpreterTest { testFile("simple.repl"); } + @Test + public void function() { + testFile("function.repl"); + } + + @Test + public void functionReferencesPrev() { + testFile("functionReferencesPrev.repl"); + } + + } diff --git a/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java b/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java index c408565fa4b..61d1eb9d1ed 100644 --- a/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java +++ b/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java @@ -89,6 +89,7 @@ public class AllInjectorsGenerator { generator.addPublicField(JavaBridgeConfiguration.class); generator.addField(JavaDescriptorResolver.class); generator.addField(PsiClassFinderForJvm.class); + generator.addPublicField(NamespaceFactoryImpl.class); generator.generate("compiler/frontend.java/src", "org.jetbrains.jet.di", "InjectorForTopDownAnalyzerForJvm"); }