working on REPL: test template and basic analyzer hacks

This commit is contained in:
Stepan Koltsov
2012-06-06 23:58:21 +04:00
parent bfec04f319
commit bace845b49
6 changed files with 300 additions and 0 deletions
@@ -0,0 +1,124 @@
/*
* 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.base.Predicates;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
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.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.di.InjectorForTopDownAnalyzerForJvm;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
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.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.name.Name;
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.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Collections;
/**
* @author Stepan Koltsov
*/
public class ReplInterpreter {
private int lineNumber = 0;
@NotNull
private final InjectorForTopDownAnalyzerForJvm injector;
@NotNull
private final JetCoreEnvironment jetCoreEnvironment;
@NotNull
private final BindingTraceContext trace;
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("<repl>"));
TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(
Predicates.<PsiFile>alwaysTrue(),
false,
true,
Collections.<AnalyzerScriptParameter>emptyList());
injector = new InjectorForTopDownAnalyzerForJvm(project, topDownAnalysisParameters, trace, module, compilerDependencies);
}
public Object eval(@NotNull String 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);
AnalyzingUtils.checkForSyntacticErrors(psiFile);
injector.getTopDownAnalyzer().prepareForTheNextReplLine();
injector.getTopDownAnalyzer().analyzeFiles(Collections.singletonList(psiFile), Collections.<AnalyzerScriptParameter>emptyList());
AnalyzingUtils.throwExceptionOnErrors(trace.getBindingContext());
Progress backendProgress = new Progress() {
@Override
public void log(String message) {
}
};
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);
try {
Class<?> scriptClass = new GeneratedClassLoader(generationState.getFactory()).loadClass("Script");
Constructor<?> scriptInstanceConstructor = scriptClass.getConstructor(new Class<?>[0]);
Object scriptInstance = scriptInstanceConstructor.newInstance(new Object[0]);
Field rvField = scriptClass.getDeclaredField("rv");
rvField.setAccessible(true);
Object rv = rvField.get(scriptInstance);
return rv;
} catch (Exception e) {
throw ExceptionUtils.rethrow(e);
}
}
}
@@ -298,6 +298,12 @@ public class TopDownAnalyzer {
}
public void prepareForTheNextReplLine() {
context.getScriptScopes().clear();
context.getScripts().clear();
}
}
+4
View File
@@ -0,0 +1,4 @@
>>> 1
1
>>> "aa"
aa
+4
View File
@@ -0,0 +1,4 @@
>>> 12 + 13
25
>>> "foo ${1 + 2}"
foo 3
@@ -0,0 +1,79 @@
/*
* 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.repl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.CompileCompilerDependenciesTest;
import org.jetbrains.jet.cli.jvm.repl.ReplInterpreter;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
/**
* @author Stepan Koltsov
*/
public class ReplInterpreterTest {
static {
System.setProperty("java.awt.headless", "true");
}
private final Disposable disposable = new Disposable() {
@Override
public void dispose() {
}
};
@After
public void tearDown() {
Disposer.dispose(disposable);
}
private void testFile(@NotNull String relativePath) {
CompilerDependencies compilerDependencies = CompileCompilerDependenciesTest.compilerDependenciesForTests(CompilerSpecialMode.JDK_HEADERS, false);
ReplInterpreter repl = new ReplInterpreter(disposable, compilerDependencies);
ReplSessionTestFile file = ReplSessionTestFile.load(new File("compiler/testData/repl/" + relativePath));
for (Pair<String, String> t : file.getLines()) {
String code = t.first;
String expected = t.second;
Object actual = repl.eval(code);
String actualString = actual != null ? actual.toString() : "null";
Assert.assertEquals("after evaluation of: " + code, actualString, expected);
}
}
@Test
public void constants() {
testFile("constants.repl");
}
@Test
public void simple() {
testFile("simple.repl");
}
}
@@ -0,0 +1,83 @@
/*
* 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.repl;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
/**
* @author Stepan Koltsov
*/
public class ReplSessionTestFile {
@NotNull
private final List<Pair<String, String>> lines;
public ReplSessionTestFile(@NotNull List<Pair<String, String>> lines) {
this.lines = lines;
}
@NotNull
public List<Pair<String, String>> getLines() {
return lines;
}
public static ReplSessionTestFile load(@NotNull File file) {
try {
FileInputStream inputStream = new FileInputStream(file);
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
return load(reader);
} finally {
inputStream.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static ReplSessionTestFile load(@NotNull BufferedReader reader) throws IOException {
List<Pair<String, String>> list = Lists.newArrayList();
while (true) {
String odd = reader.readLine();
if (odd == null) {
return new ReplSessionTestFile(list);
}
if (!odd.startsWith(">>> ")) {
throw new IllegalStateException("odd lines must start with >>>");
}
String code = odd.substring(4);
String even = reader.readLine();
if (even == null) {
throw new IllegalStateException("expecting even");
}
list.add(Pair.create(code, even));
}
}
}