@Nullable private static AnalyzeExhaust analyze( final K2JVMCompileEnvironmentConfiguration configuration, boolean stubs) { final JetCoreEnvironment environment = configuration.getEnvironment(); AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(configuration.getMessageCollector()); final Predicate<PsiFile> filesToAnalyzeCompletely = stubs ? Predicates.<PsiFile>alwaysFalse() : Predicates.<PsiFile>alwaysTrue(); analyzerWithCompilerReport.analyzeAndReport( new Function0<AnalyzeExhaust>() { @NotNull @Override public AnalyzeExhaust invoke() { return AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration( environment.getProject(), environment.getSourceFiles(), filesToAnalyzeCompletely, JetControlFlowDataTraceFactory.EMPTY, configuration.getEnvironment().getCompilerDependencies()); } }, environment.getSourceFiles()); return analyzerWithCompilerReport.hasErrors() ? null : analyzerWithCompilerReport.getAnalyzeExhaust(); }
@Nullable private ScriptDescriptor doAnalyze( @NotNull JetFile psiFile, @NotNull MessageCollector messageCollector) { WritableScope scope = new WritableScopeImpl( JetScope.EMPTY, module, new TraceBasedRedeclarationHandler(trace), "Root scope in analyzePackage"); scope.changeLockLevel(WritableScope.LockLevel.BOTH); // Import a scope that contains all top-level packages that come from dependencies // This makes the packages visible at all, does not import themselves scope.importScope(module.getPackage(FqName.ROOT).getMemberScope()); if (lastLineScope != null) { scope.importScope(lastLineScope); } scope.changeLockLevel(WritableScope.LockLevel.READING); // dummy builder is used because "root" is module descriptor, // packages added to module explicitly in injector .getTopDownAnalyzer() .doProcess( topDownAnalysisContext, scope, new PackageLikeBuilderDummy(), Collections.singletonList(psiFile)); boolean hasErrors = AnalyzerWithCompilerReport.reportDiagnostics(trace.getBindingContext(), messageCollector); if (hasErrors) { return null; } ScriptDescriptor scriptDescriptor = topDownAnalysisContext.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; }
@NotNull public LineResult eval(@NotNull String line) { ++lineNumber; FqName scriptFqName = new FqName("Line" + lineNumber); Type scriptClassType = asmTypeByFqNameWithoutInnerClasses(scriptFqName); StringBuilder fullText = new StringBuilder(); for (String prevLine : previousIncompleteLines) { fullText.append(prevLine + "\n"); } fullText.append(line); LightVirtualFile virtualFile = new LightVirtualFile( "line" + lineNumber + JetParserDefinition.STD_SCRIPT_EXT, JetLanguage.INSTANCE, fullText.toString()); virtualFile.setCharset(CharsetToolkit.UTF8_CHARSET); JetFile psiFile = (JetFile) ((PsiFileFactoryImpl) PsiFileFactory.getInstance(jetCoreEnvironment.getProject())) .trySetupPsiForFile(virtualFile, JetLanguage.INSTANCE, true, false); MessageCollectorToString errorCollector = new MessageCollectorToString(); AnalyzerWithCompilerReport.SyntaxErrorReport syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorCollector); if (syntaxErrorReport.isOnlyErrorAtEof()) { previousIncompleteLines.add(line); return LineResult.incomplete(); } previousIncompleteLines.clear(); if (syntaxErrorReport.isHasErrors()) { return LineResult.error(errorCollector.getString()); } prepareForTheNextReplLine(topDownAnalysisContext); trace.clearDiagnostics(); psiFile.getScript().putUserData(ScriptHeaderResolver.PRIORITY_KEY, lineNumber); ScriptDescriptor scriptDescriptor = doAnalyze(psiFile, errorCollector); if (scriptDescriptor == null) { return LineResult.error(errorCollector.getString()); } List<Pair<ScriptDescriptor, Type>> earlierScripts = Lists.newArrayList(); for (EarlierLine earlierLine : earlierLines) { earlierScripts.add( Pair.create(earlierLine.getScriptDescriptor(), earlierLine.getClassType())); } BindingContext bindingContext = AnalyzeExhaust.success(trace.getBindingContext(), module).getBindingContext(); GenerationState generationState = new GenerationState( psiFile.getProject(), ClassBuilderFactories.BINARIES, bindingContext, Collections.singletonList(psiFile), CompilerArgumentsUtil.DEFAULT_INLINE_FLAG); compileScript( psiFile.getScript(), scriptClassType, earlierScripts, generationState, CompilationErrorHandler.THROW_EXCEPTION); for (OutputFile outputFile : generationState.getFactory().asList()) { classLoader.addClass( JvmClassName.byInternalName(outputFile.getRelativePath().replaceFirst("\\.class$", "")), outputFile.asByteArray()); } try { Class<?> scriptClass = classLoader.loadClass(scriptFqName.asString()); 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; try { scriptInstance = scriptInstanceConstructor.newInstance(constructorArgs); } catch (Throwable e) { return LineResult.error(Throwables.getStackTraceAsString(e)); } Field rvField = scriptClass.getDeclaredField("rv"); rvField.setAccessible(true); Object rv = rvField.get(scriptInstance); earlierLines.add( new EarlierLine(line, scriptDescriptor, scriptClass, scriptInstance, scriptClassType)); return LineResult.successful( rv, KotlinBuiltIns.getInstance() .getUnitType() .equals(scriptDescriptor.getScriptCodeDescriptor().getReturnType())); } catch (Throwable e) { PrintWriter writer = new PrintWriter(System.err); classLoader.dumpClasses(writer); writer.flush(); throw UtilsPackage.rethrow(e); } }