From 46326fe5ace466e1266f1f8b7d27d3e6d5455925 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Thu, 4 Dec 2014 13:52:23 +0300 Subject: [PATCH] JS backend: report backend diagnostics --- .../jetbrains/jet/cli/js/K2JSCompiler.java | 39 +++++++---------- .../jet/lang/diagnostics/DiagnosticUtils.java | 9 ++++ .../src/org/jetbrains/k2js/config/Config.java | 11 +---- .../org/jetbrains/k2js/test/BasicTest.java | 13 +++--- .../jetbrains/k2js/facade/K2JSTranslator.java | 37 ++++++++++------ .../src/org/jetbrains/k2js/facade/Status.kt | 42 +++++++++++++++++++ .../k2js/translate/general/Translation.java | 9 +--- 7 files changed, 102 insertions(+), 58 deletions(-) create mode 100644 js/js.translator/src/org/jetbrains/k2js/facade/Status.kt 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 9fa9e188a9e..7d0eab8fcaf 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java @@ -50,11 +50,12 @@ import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.config.Services; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.Diagnostics; import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.k2js.analyze.TopDownAnalyzerFacadeForJS; import org.jetbrains.k2js.config.*; import org.jetbrains.k2js.facade.MainCallParameters; +import org.jetbrains.k2js.facade.Status; import java.io.File; import java.util.List; @@ -149,15 +150,22 @@ public class K2JSCompiler extends CLICompiler { } MainCallParameters mainCallParameters = createMainCallParameters(arguments.main); - BindingTraceContext trace = new BindingTraceContext(); - config.setTrace(trace); - OutputFileCollection outputFiles = translate(mainCallParameters, config, sourcesFiles, outputFile, outputPrefixFile, outputPostfixFile); + Status status; - Diagnostics diagnostics = trace.getBindingContext().getDiagnostics(); - if (AnalyzerWithCompilerReport.reportDiagnostics(diagnostics, messageCollector)) { - return ExitCode.COMPILATION_ERROR; + try { + //noinspection unchecked + status = translateWithMainCallParameters(mainCallParameters, sourcesFiles, outputFile, outputPrefixFile, outputPostfixFile, + config, Consumer.EMPTY_CONSUMER); + } catch (Exception e) { + throw new RuntimeException(e); } + Diagnostics diagnostics = config.getTrace().getBindingContext().getDiagnostics(); + AnalyzerWithCompilerReport.reportDiagnostics(diagnostics, messageCollector); + + if (status.isFail()) return ExitCode.COMPILATION_ERROR; + + OutputFileCollection outputFiles = status.getResult(); if (outputFile.isDirectory()) { messageCollector.report(CompilerMessageSeverity.ERROR, "Cannot open output file '" + outputFile.getPath() + "': is a directory", @@ -190,23 +198,6 @@ public class K2JSCompiler extends CLICompiler { CompilerMessageLocation.NO_LOCATION); } - private static OutputFileCollection translate( - @NotNull MainCallParameters mainCall, - @NotNull Config config, - @NotNull List sourceFiles, - @NotNull File outputFile, - @Nullable File outputPrefix, - @Nullable File outputPostfix - ) { - try { - //noinspection unchecked - return translateWithMainCallParameters(mainCall, sourceFiles, outputFile, outputPrefix, outputPostfix, config, Consumer.EMPTY_CONSUMER); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - private static boolean analyzeAndReportErrors(@NotNull MessageCollector messageCollector, @NotNull final List sources, @NotNull final Config config) { AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticUtils.java index 7924e81b4c0..382cab80f58 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/DiagnosticUtils.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils; +import org.jetbrains.jet.lang.resolve.Diagnostics; import java.util.Collection; import java.util.Collections; @@ -210,4 +211,12 @@ public class DiagnosticUtils { return "(" + line + "," + column + ")"; } } + + public static boolean hasError(Diagnostics diagnostics) { + for (Diagnostic diagnostic : diagnostics.all()) { + if (diagnostic.getSeverity() == Severity.ERROR) return true; + } + + return false; + } } diff --git a/js/js.frontend/src/org/jetbrains/k2js/config/Config.java b/js/js.frontend/src/org/jetbrains/k2js/config/Config.java index 33936f577c1..10b84dd7f26 100644 --- a/js/js.frontend/src/org/jetbrains/k2js/config/Config.java +++ b/js/js.frontend/src/org/jetbrains/k2js/config/Config.java @@ -23,13 +23,10 @@ import kotlin.Unit; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.diagnostics.Diagnostic; -import org.jetbrains.jet.lang.diagnostics.DiagnosticSink; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; import java.util.Collection; import java.util.List; @@ -53,7 +50,7 @@ public abstract class Config { private final boolean sourcemap; @NotNull - private DiagnosticSink trace = new BindingTraceContext(); + private final BindingTrace trace = new BindingTraceContext(); public Config( @NotNull Project project, @@ -111,14 +108,10 @@ public abstract class Config { } @NotNull - public DiagnosticSink getTrace() { + public BindingTrace getTrace() { return trace; } - public void setTrace(@NotNull DiagnosticSink trace) { - this.trace = trace; - } - @Nullable public ModuleDescriptor getLibraryModule() { return null; diff --git a/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java b/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java index cab1cd4ddef..6d4940f4732 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java @@ -43,6 +43,7 @@ import org.jetbrains.k2js.JavaScript; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.config.LibrarySourcesConfigWithCaching; +import org.jetbrains.k2js.facade.Status; import org.jetbrains.k2js.facade.MainCallParameters; import org.jetbrains.k2js.test.rhino.RhinoResultChecker; import org.jetbrains.k2js.test.utils.JsTestUtils; @@ -161,15 +162,15 @@ public abstract class BasicTest extends KotlinTestWithEnvironment { @NotNull MainCallParameters mainCallParameters, @NotNull Config config ) throws Exception { - //noinspection unchecked - OutputFileCollection outputFiles = - translateWithMainCallParameters(mainCallParameters, jetFiles, outputFile, - getOutputPrefixFile(), getOutputPostfixFile(), - config, getConsumer()); + Status status = translateWithMainCallParameters(mainCallParameters, jetFiles, outputFile, + getOutputPrefixFile(), getOutputPostfixFile(), + config, getConsumer()); + + if (status.isFail()) return; File outputDir = outputFile.getParentFile(); assert outputDir != null : "Parent file for output file should not be null, outputFilePath: " + outputFile.getPath(); - OutputUtilsPackage.writeAllTo(outputFiles, outputDir); + OutputUtilsPackage.writeAllTo(status.getResult(), outputDir); } protected File getOutputPostfixFile() { 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 d53c8ddce7b..2899347859f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -38,6 +38,7 @@ import org.jetbrains.jet.analyzer.AnalysisResult; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.Diagnostics; import org.jetbrains.jet.utils.fileUtils.FileUtilsPackage; import org.jetbrains.js.compiler.JsSourceGenerationVisitor; import org.jetbrains.js.compiler.sourcemap.SourceMap3Builder; @@ -45,6 +46,7 @@ import org.jetbrains.js.compiler.sourcemap.SourceMapBuilder; import org.jetbrains.k2js.analyze.TopDownAnalyzerFacadeForJS; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.facade.exceptions.TranslationException; +import org.jetbrains.k2js.inline.JsInliner; import org.jetbrains.k2js.translate.general.Translation; import java.io.File; @@ -52,6 +54,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; +import static org.jetbrains.jet.lang.diagnostics.DiagnosticUtils.hasError; import static org.jetbrains.jet.lang.psi.PsiPackage.JetPsiFactory; import static org.jetbrains.k2js.facade.FacadeUtils.parseString; @@ -63,7 +66,7 @@ public final class K2JSTranslator { public static final String FLUSH_SYSTEM_OUT = "Kotlin.out.flush();\n"; public static final String GET_SYSTEM_OUT = "Kotlin.out.buffer;\n"; - public static OutputFileCollection translateWithMainCallParameters( + public static Status translateWithMainCallParameters( @NotNull MainCallParameters mainCall, @NotNull List files, @NotNull File outputFile, @@ -75,8 +78,11 @@ public final class K2JSTranslator { K2JSTranslator translator = new K2JSTranslator(config); TextOutputImpl output = new TextOutputImpl(); SourceMapBuilder sourceMapBuilder = config.isSourcemap() ? new SourceMap3Builder(outputFile, output, new SourceMapBuilderConsumer()) : null; - String programCode = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder, astConsumer); + Status codeStatus = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder, astConsumer); + if (codeStatus.isFail()) return Status.fail(); + + String programCode = codeStatus.getResult(); String prefix = FileUtilsPackage.readTextOrEmpty(outputPrefixFile); String postfix = FileUtilsPackage.readTextOrEmpty(outputPostfixFile); @@ -101,7 +107,8 @@ public final class K2JSTranslator { outputFiles.add(sourcemapFile); } - return new SimpleOutputFileCollection(outputFiles); + OutputFileCollection outputFileCollection = new SimpleOutputFileCollection(outputFiles); + return Status.success(outputFileCollection); } @NotNull @@ -114,26 +121,30 @@ public final class K2JSTranslator { //NOTE: web demo related method @SuppressWarnings("UnusedDeclaration") @NotNull - public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { + public Status translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { JetFile file = JetPsiFactory(getProject()).createFile("test", programText); - String programCode = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString))) + "\n"; - return FLUSH_SYSTEM_OUT + programCode + GET_SYSTEM_OUT; + Status status = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString))); + + if (status.isFail()) return status; + + String code = FLUSH_SYSTEM_OUT + status.getResult() + "\n" + GET_SYSTEM_OUT; + return Status.success(code); } @NotNull - public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException { + public Status 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) + public Status generateProgramCode(@NotNull List files, @NotNull MainCallParameters mainCallParameters) throws TranslationException { //noinspection unchecked return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null, Consumer.EMPTY_CONSUMER); } @NotNull - public String generateProgramCode( + public Status generateProgramCode( @NotNull List files, @NotNull MainCallParameters mainCallParameters, @NotNull TextOutputImpl output, @@ -141,13 +152,15 @@ public final class K2JSTranslator { @NotNull Consumer astConsumer ) throws TranslationException { JsProgram program = generateProgram(files, mainCallParameters); + Diagnostics diagnostics = config.getTrace().getBindingContext().getDiagnostics(); - JsSourceGenerationVisitor sourceGenerator = new JsSourceGenerationVisitor(output, sourceMapBuilder); - program.accept(sourceGenerator); + if (hasError(diagnostics)) return Status.fail(); + program = JsInliner.process(program); + program.accept(new JsSourceGenerationVisitor(output, sourceMapBuilder)); astConsumer.consume(program); - return output.toString(); + return Status.success(output.toString()); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/Status.kt b/js/js.translator/src/org/jetbrains/k2js/facade/Status.kt new file mode 100644 index 00000000000..2e4b4c5f9c6 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/facade/Status.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2014 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.k2js.facade + +import kotlin.platform.platformStatic + +public class Status private (private val _result: T, private val type: Status.Type) { + class object { + platformStatic fun fail(): Status = Status(null, Type.Fail) + + platformStatic fun success(value: T): Status = Status(value, Type.Success) + } + + public val result: T + get() { + assert(type == Type.Success) { "Getting result from fail status is illegal" } + return _result + } + + public fun isFail(): Boolean = type == Type.Fail + + public fun isSuccess(): Boolean = type == Type.Success + + private enum class Type { + Fail + Success + } +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index 14017c18822..36cce97a54b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -30,11 +30,7 @@ import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPacka import org.jetbrains.jet.plugin.MainFunctionDetector; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.facade.MainCallParameters; -import org.jetbrains.k2js.facade.exceptions.MainFunctionNotFoundException; -import org.jetbrains.k2js.facade.exceptions.TranslationException; -import org.jetbrains.k2js.facade.exceptions.TranslationInternalException; -import org.jetbrains.k2js.facade.exceptions.UnsupportedFeatureException; -import org.jetbrains.k2js.inline.JsInliner; +import org.jetbrains.k2js.facade.exceptions.*; import org.jetbrains.k2js.translate.callTranslator.CallTranslator; import org.jetbrains.k2js.translate.context.Namer; import org.jetbrains.k2js.translate.context.StaticContext; @@ -168,8 +164,7 @@ public final class Translation { @NotNull Config config) throws TranslationException { try { - JsProgram program = doGenerateAst(bindingContext, files, mainCallParameters, moduleDescriptor, config); - return config.isInlineEnabled() ? JsInliner.process(program) : program; + return doGenerateAst(bindingContext, files, mainCallParameters, moduleDescriptor, config); } catch (UnsupportedOperationException e) { throw new UnsupportedFeatureException("Unsupported feature used.", e);