From 3ba9ad5f95c31592158e656e2210ccff839227b3 Mon Sep 17 00:00:00 2001 From: develar Date: Fri, 23 Nov 2012 20:01:28 +0400 Subject: [PATCH] fix JS analyzer, split binding context to lib and sources --- .../messages/AnalyzerWithCompilerReport.java | 10 +-- .../jetbrains/jet/cli/js/K2JSCompiler.java | 81 +++++++++---------- .../compiler/KotlinToJVMBytecodeCompiler.java | 4 +- .../jet/lang/resolve/DescriptorUtils.java | 5 -- .../jet/plugin/compiler/K2JSCompiler.java | 10 +-- .../k2js/test/utils/TranslationUtils.java | 3 +- .../k2js/analyze/AnalyzerFacadeForJS.java | 58 ++++++++----- .../k2js/analyze/JsConfiguration.java | 17 ++-- .../k2js/analyze/JsModuleConfiguration.java | 65 +++++++++++++++ .../jetbrains/k2js/facade/K2JSTranslator.java | 53 +++++------- .../reference/PropertyAccessTranslator.java | 60 ++++---------- .../QualifiedExpressionTranslator.java | 36 ++++++--- .../reference/ReferenceAccessTranslator.java | 12 +-- .../reference/ReferenceTranslator.java | 17 ++-- 14 files changed, 226 insertions(+), 205 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/k2js/analyze/JsModuleConfiguration.java diff --git a/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java b/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java index 59495aa123809..b99c0e129b074 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/common/messages/AnalyzerWithCompilerReport.java @@ -207,24 +207,20 @@ public void visitErrorElement(PsiErrorElement element) { return new SyntaxErrorReport(visitor.hasErrors, visitor.onlyErrorAtEof); } - @Nullable - public AnalyzeExhaust getAnalyzeExhaust() { - return analyzeExhaust; - } - public boolean hasErrors() { return hasErrors; } - public void analyzeAndReport(@NotNull Function0 analyzer, @NotNull Collection files) { + @Nullable + public AnalyzeExhaust analyzeAndReport(@NotNull Function0 analyzer, @NotNull Collection files) { reportSyntaxErrors(files); analyzeExhaust = analyzer.invoke(); reportDiagnostics(analyzeExhaust.getBindingContext(), messageCollectorWrapper); reportIncompleteHierarchies(); reportAlternativeSignatureErrors(); + return hasErrors() ? null : analyzeExhaust; } - private static class MyDiagnostic extends SimpleDiagnostic { private String message; diff --git a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java index c962fb4f2febd..f9a15f8be548a 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java @@ -18,27 +18,23 @@ import com.google.common.base.Function; import com.google.common.base.Joiner; -import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; import jet.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.cli.common.CLICompiler; import org.jetbrains.jet.cli.common.ExitCode; -import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport; -import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.jet.cli.common.messages.PrintingMessageCollector; +import org.jetbrains.jet.cli.common.messages.*; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.config.CommonConfigurationKeys; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS; import org.jetbrains.k2js.config.*; import org.jetbrains.k2js.facade.K2JSTranslator; @@ -65,7 +61,6 @@ protected K2JSCompilerArguments createArguments() { return new K2JSCompilerArguments(); } - @NotNull @Override protected ExitCode doExecute(K2JSCompilerArguments arguments, PrintingMessageCollector messageCollector, Disposable rootDisposable) { @@ -73,6 +68,11 @@ protected ExitCode doExecute(K2JSCompilerArguments arguments, PrintingMessageCol messageCollector.report(CompilerMessageSeverity.ERROR, "Specify sources location via -sourceFiles", NO_LOCATION); return ExitCode.INTERNAL_ERROR; } + String outputFile = arguments.outputFile; + if (outputFile == null) { + messageCollector.report(CompilerMessageSeverity.ERROR, "Specify output file via -output", CompilerMessageLocation.NO_LOCATION); + return ExitCode.INTERNAL_ERROR; + } CompilerConfiguration configuration = new CompilerConfiguration(); configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, Arrays.asList(arguments.sourceFiles)); @@ -81,26 +81,46 @@ protected ExitCode doExecute(K2JSCompilerArguments arguments, PrintingMessageCol Project project = environmentForJS.getProject(); ClassPathLibrarySourcesLoader sourceLoader = new ClassPathLibrarySourcesLoader(project); - List sourceFiles = sourceLoader.findSourceFiles(); - environmentForJS.getSourceFiles().addAll(sourceFiles); + environmentForJS.getSourceFiles().addAll(sourceLoader.findSourceFiles()); if (arguments.isVerbose()) { reportCompiledSourcesList(messageCollector, environmentForJS); } - Config config = getConfig(arguments, project); - if (analyzeAndReportErrors(messageCollector, environmentForJS.getSourceFiles(), config)) { + final Config config = getConfig(arguments, project); + final List sources = environmentForJS.getSourceFiles(); + AnalyzeExhaust libraryExhaust = analyze(messageCollector, config, config.getLibFiles(), null, false); + if (libraryExhaust == null) { return ExitCode.COMPILATION_ERROR; } + libraryExhaust.throwIfError(); - String outputFile = arguments.outputFile; - if (outputFile == null) { - messageCollector.report(CompilerMessageSeverity.ERROR, "Specify output file via -output", CompilerMessageLocation.NO_LOCATION); - return ExitCode.INTERNAL_ERROR; + AnalyzeExhaust exhaust = analyze(messageCollector, config, sources, libraryExhaust.getBindingContext(), true); + if (exhaust == null) { + return ExitCode.COMPILATION_ERROR; } + exhaust.throwIfError(); MainCallParameters mainCallParameters = arguments.createMainCallParameters(); - return translateAndGenerateOutputFile(mainCallParameters, messageCollector, environmentForJS, config, outputFile); + try { + K2JSTranslator.translateWithMainCallParametersAndSaveToFile(mainCallParameters, environmentForJS.getSourceFiles(), outputFile, + config, exhaust); + } + catch (Throwable e) { + messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(e), + CompilerMessageLocation.NO_LOCATION); + return ExitCode.INTERNAL_ERROR; + } + return ExitCode.OK; + } + + private static AnalyzeExhaust analyze(PrintingMessageCollector messageCollector, final Config config, final List sources, final BindingContext parentBindingContext, final boolean analyzeCompletely) { + return new AnalyzerWithCompilerReport(messageCollector).analyzeAndReport(new Function0() { + @Override + public AnalyzeExhaust invoke() { + return AnalyzerFacadeForJS.analyzeFiles(sources, analyzeCompletely, config, parentBindingContext, false); + } + }, sources); } private static void reportCompiledSourcesList(@NotNull PrintingMessageCollector messageCollector, @@ -121,35 +141,6 @@ public String apply(@Nullable JetFile file) { CompilerMessageLocation.NO_LOCATION); } - @NotNull - private static ExitCode translateAndGenerateOutputFile(@NotNull MainCallParameters mainCall, - @NotNull PrintingMessageCollector messageCollector, - @NotNull JetCoreEnvironment environmentForJS, @NotNull Config config, @NotNull String outputFile) { - try { - K2JSTranslator.translateWithMainCallParametersAndSaveToFile(mainCall, environmentForJS.getSourceFiles(), outputFile, config); - } - catch (Exception e) { - messageCollector.report(CompilerMessageSeverity.ERROR, "Exception while translating:\n" + e.getMessage(), - CompilerMessageLocation.NO_LOCATION); - // TODO we should report the exception nicely to the collector so it can report - // for example inside a mvn plugin we need to see the stack trace - return ExitCode.INTERNAL_ERROR; - } - return ExitCode.OK; - } - - private static boolean analyzeAndReportErrors(@NotNull PrintingMessageCollector messageCollector, - @NotNull final List sources, @NotNull final Config config) { - AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector); - analyzerWithCompilerReport.analyzeAndReport(new Function0() { - @Override - public AnalyzeExhaust invoke() { - return AnalyzerFacadeForJS.analyzeFiles(sources, Predicates.alwaysTrue(), config); - } - }, sources); - return analyzerWithCompilerReport.hasErrors(); - } - @NotNull private static Config getConfig(@NotNull K2JSCompilerArguments arguments, @NotNull Project project) { EcmaVersion ecmaVersion = EcmaVersion.fromString(arguments.target); diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 1a169419a55d3..540be42f8b6ff 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -311,7 +311,7 @@ private static AnalyzeExhaust analyze( environment.getConfiguration().get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)); final Predicate filesToAnalyzeCompletely = stubs ? Predicates.alwaysFalse() : Predicates.alwaysTrue(); - analyzerWithCompilerReport.analyzeAndReport( + return analyzerWithCompilerReport.analyzeAndReport( new Function0() { @NotNull @Override @@ -325,8 +325,6 @@ public AnalyzeExhaust invoke() { } }, environment.getSourceFiles() ); - - return analyzerWithCompilerReport.hasErrors() ? null : analyzerWithCompilerReport.getAnalyzeExhaust(); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index e2ddb96368332..52f74962c1a8c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -234,11 +234,6 @@ public static void addSuperTypes(JetType type, Set set) { } } - public static boolean isTopLevelNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { - return namespaceDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor - && namespaceDescriptor.getContainingDeclaration().getContainingDeclaration() instanceof ModuleDescriptor; - } - public static boolean isRootNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) { return namespaceDescriptor.getContainingDeclaration() instanceof ModuleDescriptor; } diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java index 5879a75ebf1b7..30c5785f906dd 100644 --- a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java @@ -173,15 +173,13 @@ private static void collectModuleDependencies(Module dependentModule, Set(context); diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java index eab15f4ed68d5..4d06744dbef7b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java @@ -50,12 +50,11 @@ private AnalyzerFacadeForJS() { @NotNull public static BindingContext analyzeFilesAndCheckErrors(@NotNull List files, @NotNull Config config) { - BindingContext bindingContext = analyzeFiles(files, Predicates.alwaysTrue(), config).getBindingContext(); + BindingContext bindingContext = analyzeFiles(files, config); checkForErrors(Config.withJsLibAdded(files, config), bindingContext); return bindingContext; } - //NOTE: web demo related method @SuppressWarnings("UnusedDeclaration") @NotNull @@ -70,32 +69,26 @@ public static AnalyzeExhaust analyzeFiles( return analyzeFiles(files, filesToAnalyzeCompletely, config, false); } - //TODO: refactor @NotNull public static AnalyzeExhaust analyzeFiles( @NotNull Collection files, - @NotNull Predicate filesToAnalyzeCompletely, @NotNull Config config, - boolean storeContextForBodiesResolve) { + @NotNull Predicate filesToAnalyzeCompletely, + @NotNull Config config, + boolean storeContextForBodiesResolve + ) { Project project = config.getProject(); - - final ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); - + ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); Predicate completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely); - - TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters( - completely, false, false, Collections.emptyList()); - + TopDownAnalysisParameters topDownAnalysisParameters = + new TopDownAnalysisParameters(completely, false, false, Collections.emptyList()); BindingContext libraryBindingContext = config.getLibraryBindingContext(); BindingTrace trace = libraryBindingContext == null ? new ObservableBindingTrace(new BindingTraceContext()) : new DelegatingBindingTrace(libraryBindingContext, "trace for analyzing library in js"); - InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs( - project, topDownAnalysisParameters, trace, owner, - new JsConfiguration(project, libraryBindingContext)); + InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner, + new JsConfiguration(project, libraryBindingContext)); try { - Collection allFiles = libraryBindingContext != null ? - files : - Config.withJsLibAdded(files, config); + Collection allFiles = libraryBindingContext != null ? files : Config.withJsLibAdded(files, config); injector.getTopDownAnalyzer().analyzeFiles(allFiles, Collections.emptyList()); BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ? new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) : @@ -107,6 +100,35 @@ public static AnalyzeExhaust analyzeFiles( } } + @NotNull + public static AnalyzeExhaust analyzeFiles( + @NotNull Collection files, + boolean analyzeCompletely, + @NotNull Config config, + BindingContext parentBindingContext, + boolean storeContextForBodiesResolve + ) { + Project project = config.getProject(); + ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); + TopDownAnalysisParameters topDownAnalysisParameters = + new TopDownAnalysisParameters(analyzeCompletely ? Predicates.alwaysTrue() : Predicates.alwaysFalse(), false, false, Collections.emptyList()); + BindingTrace trace = parentBindingContext == null ? + new ObservableBindingTrace(new BindingTraceContext()) : + new DelegatingBindingTrace(parentBindingContext, "trace for analyzing library in js"); + InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs(project, topDownAnalysisParameters, trace, owner, + new JsModuleConfiguration(project, parentBindingContext)); + try { + injector.getTopDownAnalyzer().analyzeFiles(files, Collections.emptyList()); + BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ? + new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) : + null; + return AnalyzeExhaust.success(trace.getBindingContext(), bodiesResolveContext, injector.getModuleConfiguration()); + } + finally { + injector.destroy(); + } + } + @NotNull public static AnalyzeExhaust analyzeBodiesInFiles( @NotNull Predicate filesToAnalyzeCompletely, diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/JsConfiguration.java b/js/js.translator/src/org/jetbrains/k2js/analyze/JsConfiguration.java index 780b1665cc317..9a4af51efa178 100644 --- a/js/js.translator/src/org/jetbrains/k2js/analyze/JsConfiguration.java +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/JsConfiguration.java @@ -84,7 +84,11 @@ public void extendNamespaceScope(@NotNull BindingTrace trace, @NotNull Namespace } if (hasPreanalyzedContextForTests()) { - extendScopeWithPreAnalyzedContextForTests(namespaceDescriptor, namespaceMemberScope); + if (isNamespaceImportedByDefault(namespaceDescriptor) || isRootNamespace(namespaceDescriptor)) { + FqName descriptorName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe(); + NamespaceDescriptor alreadyAnalyzedNamespace = preanalyzedContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, descriptorName); + namespaceMemberScope.importScope(alreadyAnalyzedNamespace.getMemberScope()); + } } } @@ -92,17 +96,6 @@ private boolean hasPreanalyzedContextForTests() { return preanalyzedContext != null; } - /*NOTE: this code is wrong. Check it if you have tests failing for frontend reasons*/ - @SuppressWarnings("ConstantConditions") - private void extendScopeWithPreAnalyzedContextForTests(@NotNull NamespaceDescriptor namespaceDescriptor, - @NotNull WritableScope namespaceMemberScope) { - if (isNamespaceImportedByDefault(namespaceDescriptor) || isRootNamespace(namespaceDescriptor)) { - FqName descriptorName = DescriptorUtils.getFQName(namespaceDescriptor).toSafe(); - NamespaceDescriptor alreadyAnalyzedNamespace = preanalyzedContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, descriptorName); - namespaceMemberScope.importScope(alreadyAnalyzedNamespace.getMemberScope()); - } - } - private static boolean isNamespaceImportedByDefault(@NotNull NamespaceDescriptor namespaceDescriptor) { for (ImportPath path : DEFAULT_IMPORT_PATHS) { if (path.fqnPart().equals(DescriptorUtils.getFQName(namespaceDescriptor).toSafe())) { diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/JsModuleConfiguration.java b/js/js.translator/src/org/jetbrains/k2js/analyze/JsModuleConfiguration.java new file mode 100644 index 0000000000000..ebbcc13b19bdf --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/JsModuleConfiguration.java @@ -0,0 +1,65 @@ +package org.jetbrains.k2js.analyze; + +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.DefaultModuleConfiguration; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.jet.lang.PlatformToKotlinClassMap; +import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.psi.JetImportDirective; +import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.ImportPath; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; + +import java.util.Collection; + +public class JsModuleConfiguration implements ModuleConfiguration { + private final Project project; + private final BindingContext parentBindingContext; + private final ModuleConfiguration delegateConfiguration; + + public JsModuleConfiguration(@NotNull Project project, BindingContext parentBindingContext) { + this.project = project; + this.parentBindingContext = parentBindingContext; + this.delegateConfiguration = DefaultModuleConfiguration.createStandardConfiguration(project); + } + + @Override + public void addDefaultImports(@NotNull Collection directives) { + for (ImportPath path : JsConfiguration.DEFAULT_IMPORT_PATHS) { + directives.add(JetPsiFactory.createImportDirective(project, path)); + } + delegateConfiguration.addDefaultImports(directives); + } + + @Override + public void extendNamespaceScope( + @NotNull BindingTrace trace, @NotNull NamespaceDescriptor namespaceDescriptor, @NotNull WritableScope namespaceMemberScope + ) { + if (parentBindingContext != null) { + FqName qualifiedName = namespaceDescriptor.getQualifiedName(); + NamespaceDescriptor alreadyAnalyzedNamespace = + parentBindingContext.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, qualifiedName); + if (alreadyAnalyzedNamespace != null) { + namespaceMemberScope.importScope(alreadyAnalyzedNamespace.getMemberScope()); + } + } + else if (DescriptorUtils.isRootNamespace(namespaceDescriptor)) { + namespaceMemberScope.importScope(KotlinBuiltIns.getInstance().getBuiltInsScope()); + } + else { + delegateConfiguration.extendNamespaceScope(trace, namespaceDescriptor, namespaceMemberScope); + } + } + + @NotNull + @Override + public PlatformToKotlinClassMap getPlatformToKotlinClassMap() { + return PlatformToKotlinClassMap.EMPTY; + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index fc517f56195b5..8a704af23c05b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -18,10 +18,10 @@ import com.google.dart.compiler.backend.js.ast.JsProgram; import com.google.dart.compiler.util.TextOutputImpl; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -47,29 +47,29 @@ * An entry point of translator. */ public final class K2JSTranslator { - public static final String FLUSH_SYSTEM_OUT = "Kotlin.System.flush();\n"; public static final String GET_SYSTEM_OUT = "Kotlin.System.output();\n"; - public static void translateWithMainCallParametersAndSaveToFile(@NotNull MainCallParameters mainCall, + @NotNull + private final Config config; + + public static void translateWithMainCallParametersAndSaveToFile( + @NotNull MainCallParameters mainCall, @NotNull List files, @NotNull String outputPath, - @NotNull Config config) throws TranslationException, IOException { + @NotNull Config config, AnalyzeExhaust exhaust + ) throws TranslationException, IOException { K2JSTranslator translator = new K2JSTranslator(config); File outFile = new File(outputPath); TextOutputImpl output = new TextOutputImpl(); SourceMapBuilder sourceMapBuilder = config.isSourcemap() ? new SourceMap3Builder(outFile, output, new SourceMapBuilderConsumer()) : null; - String programCode = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder); + String programCode = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder, exhaust); FileUtil.writeToFile(outFile, programCode); if (sourceMapBuilder != null) { FileUtil.writeToFile(sourceMapBuilder.getOutFile(), sourceMapBuilder.build()); } } - @NotNull - private final Config config; - - public K2JSTranslator(@NotNull Config config) { this.config = config; } @@ -78,46 +78,31 @@ public K2JSTranslator(@NotNull Config config) { @SuppressWarnings("UnusedDeclaration") @NotNull public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { - JetFile file = JetFileUtils.createPsiFile("test", programText, getProject()); - String programCode = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString))) + "\n"; + JetFile file = JetFileUtils.createPsiFile("test", programText, config.getProject()); + String programCode = generateProgramCode(Collections.singletonList(file), + MainCallParameters.mainWithArguments(parseString(argumentsString))) + "\n"; return FLUSH_SYSTEM_OUT + programCode + GET_SYSTEM_OUT; } - @NotNull - public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException { - return generateProgramCode(Collections.singletonList(file), mainCallParameters); - } - @NotNull public String generateProgramCode(@NotNull List files, @NotNull MainCallParameters mainCallParameters) throws TranslationException { - return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null); + KotlinBuiltIns.initialize(config.getProject()); + return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null, null); } @NotNull - public String generateProgramCode( + private String generateProgramCode( @NotNull List files, @NotNull MainCallParameters mainCallParameters, @NotNull TextOutputImpl output, - @Nullable SourceMapBuilder sourceMapBuilder + @Nullable SourceMapBuilder sourceMapBuilder, + AnalyzeExhaust exhaust ) throws TranslationException { - JsProgram program = generateProgram(files, mainCallParameters); + BindingContext bindingContext = exhaust == null ? AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(files, config) : exhaust.getBindingContext(); + JsProgram program = Translation.generateAst(bindingContext, files, mainCallParameters, config); JsSourceGenerationVisitor sourceGenerator = new JsSourceGenerationVisitor(output, sourceMapBuilder); program.accept(sourceGenerator); return output.toString(); } - - @NotNull - public JsProgram generateProgram(@NotNull List filesToTranslate, - @NotNull MainCallParameters mainCallParameters) - throws TranslationException { - KotlinBuiltIns.initialize(config.getProject()); - BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); - return Translation.generateAst(bindingContext, filesToTranslate, mainCallParameters, config); - } - - @NotNull - private Project getProject() { - return config.getProject(); - } } \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java index 8dd6995617bbf..cb9dfe9d66424 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/PropertyAccessTranslator.java @@ -21,8 +21,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.k2js.translate.context.TranslationContext; @@ -31,21 +29,31 @@ import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isNativeObject; import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForProperty; -import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName; import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference; /** * @author Pavel Talanov */ public abstract class PropertyAccessTranslator extends AbstractTranslator implements AccessTranslator { + @NotNull + public static PropertyAccessTranslator newInstance( + @NotNull JetSimpleNameExpression expression, + @Nullable JsExpression qualifier, + @NotNull CallType callType, + @NotNull TranslationContext context + ) { + return newInstance(expression, qualifier, callType, context, getPropertyDescriptor(expression, context)); + } @NotNull - public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, + public static PropertyAccessTranslator newInstance( + @NotNull JetSimpleNameExpression expression, @Nullable JsExpression qualifier, @NotNull CallType callType, - @NotNull TranslationContext context) { + @NotNull TranslationContext context, + @NotNull PropertyDescriptor propertyDescriptor + ) { PropertyAccessTranslator result; - PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context); if (isNativeObject(propertyDescriptor) || isBackingFieldReference(expression)) { result = new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context); } @@ -66,46 +74,6 @@ private static PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameEx return (PropertyDescriptor) descriptor; } - - @NotNull - public static JsExpression translateAsPropertyGetterCall(@NotNull JetSimpleNameExpression expression, - @Nullable JsExpression qualifier, - @NotNull CallType callType, - @NotNull TranslationContext context) { - return (newInstance(expression, qualifier, callType, context)) - .translateAsGet(); - } - - - private static boolean canBePropertyGetterCall(@NotNull JetQualifiedExpression expression, - @NotNull TranslationContext context) { - JetSimpleNameExpression selector = getSelectorAsSimpleName(expression); - assert selector != null : "Only names are allowed after the dot"; - return canBePropertyGetterCall(selector, context); - } - - private static boolean canBePropertyGetterCall(@NotNull JetSimpleNameExpression expression, - @NotNull TranslationContext context) { - return (getDescriptorForReferenceExpression - (context.bindingContext(), expression) instanceof PropertyDescriptor); - } - - public static boolean canBePropertyGetterCall(@NotNull JetExpression expression, - @NotNull TranslationContext context) { - if (expression instanceof JetQualifiedExpression) { - return canBePropertyGetterCall((JetQualifiedExpression) expression, context); - } - if (expression instanceof JetSimpleNameExpression) { - return canBePropertyGetterCall((JetSimpleNameExpression) expression, context); - } - return false; - } - - public static boolean canBePropertyAccess(@NotNull JetExpression expression, - @NotNull TranslationContext context) { - return canBePropertyGetterCall(expression, context); - } - //TODO: we use normal by default but may cause bugs //TODO: inspect private /*var*/ CallType callType = CallType.NORMAL; diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java index 960dd1c7a9896..e2ee7ddd75ff4 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.utils.ErrorReportingUtils; @@ -29,6 +30,7 @@ import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector; import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector; +import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName; /** * @author Pavel Talanov @@ -61,23 +63,37 @@ public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExp @NotNull private static JsExpression dispatchToCorrectTranslator( @Nullable JsExpression receiver, - @NotNull JetExpression selector, + @NotNull JetExpression expression, @NotNull CallType callType, @NotNull TranslationContext context ) { - if (PropertyAccessTranslator.canBePropertyGetterCall(selector, context)) { - assert selector instanceof JetSimpleNameExpression : "Selectors for properties must be simple names."; - return PropertyAccessTranslator.translateAsPropertyGetterCall - ((JetSimpleNameExpression)selector, receiver, callType, context); + JetSimpleNameExpression selector; + if (expression instanceof JetQualifiedExpression) { + selector = getSelectorAsSimpleName((JetQualifiedExpression) expression); + assert selector != null : "Only names are allowed after the dot"; + } + else if (expression instanceof JetSimpleNameExpression) { + selector = (JetSimpleNameExpression) expression; } - if (selector instanceof JetCallExpression) { - return invokeCallExpressionTranslator(receiver, selector, callType, context); + else { + selector = null; + } + + if (selector != null) { + DeclarationDescriptor descriptor = getDescriptorForReferenceExpression(context.bindingContext(), selector); + if (descriptor instanceof PropertyDescriptor) { + return PropertyAccessTranslator.newInstance(selector, receiver, callType, context, (PropertyDescriptor) descriptor).translateAsGet(); + } + } + + if (expression instanceof JetCallExpression) { + return invokeCallExpressionTranslator(receiver, expression, callType, context); } //TODO: never get there - if (selector instanceof JetSimpleNameExpression) { - return ReferenceTranslator.translateSimpleName((JetSimpleNameExpression)selector, context); + if (expression instanceof JetSimpleNameExpression) { + return ReferenceTranslator.translateSimpleName((JetSimpleNameExpression)expression, context); } - throw new AssertionError("Unexpected qualified expression: " + selector.getText()); + throw new AssertionError("Unexpected qualified expression: " + expression.getText()); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java index c8e995f789cec..07b3909c3fc21 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceAccessTranslator.java @@ -19,7 +19,6 @@ import com.google.dart.compiler.backend.js.ast.JsExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.context.TemporaryVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.AbstractTranslator; @@ -29,24 +28,15 @@ import java.util.List; import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsLocalNameReference; -import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression; /** * @author Pavel Talanov */ public final class ReferenceAccessTranslator extends AbstractTranslator implements CachedAccessTranslator { - - @NotNull - /*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression, - @NotNull TranslationContext context) { - DeclarationDescriptor referenceDescriptor = getDescriptorForReferenceExpression(context.bindingContext(), expression); - return new ReferenceAccessTranslator(referenceDescriptor, context); - } - @NotNull private final JsExpression reference; - private ReferenceAccessTranslator(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) { + public ReferenceAccessTranslator(@NotNull DeclarationDescriptor descriptor, @NotNull TranslationContext context) { super(context); this.reference = translateAsLocalNameReference(descriptor, context()); } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 576b5842263ff..88d17ff019a3e 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -21,8 +21,10 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.translate.context.TranslationContext; import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference; @@ -67,15 +69,18 @@ public static AccessTranslator getAccessTranslator(@NotNull JetSimpleNameExpress } @NotNull - public static AccessTranslator getAccessTranslator(@NotNull JetSimpleNameExpression referenceExpression, + public static AccessTranslator getAccessTranslator(@NotNull JetSimpleNameExpression expression, @Nullable JsExpression receiver, @NotNull TranslationContext context) { - if (isBackingFieldReference(referenceExpression)) { - return BackingFieldAccessTranslator.newInstance(referenceExpression, context); + if (isBackingFieldReference(expression)) { + return BackingFieldAccessTranslator.newInstance(expression, context); } - if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) { - return PropertyAccessTranslator.newInstance(referenceExpression, receiver, CallType.NORMAL, context); + + DeclarationDescriptor descriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, expression); + if (descriptor instanceof PropertyDescriptor) { + return PropertyAccessTranslator.newInstance(expression, receiver, CallType.NORMAL, context, (PropertyDescriptor) descriptor); } - return ReferenceAccessTranslator.newInstance(referenceExpression, context); + assert descriptor != null; + return new ReferenceAccessTranslator(descriptor, context); } } \ No newline at end of file