From f5eb39e1f1eae198e74342f1c052038737e4ce84 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Sun, 18 Jan 2015 22:14:53 +0300 Subject: [PATCH] JS: added TranslationResult --- .../jetbrains/kotlin/cli/js/K2JSCompiler.java | 21 +++-- .../jetbrains/kotlin/js/test/BasicTest.java | 17 ++-- .../kotlin/js/facade/K2JSTranslator.java | 86 +----------------- .../org/jetbrains/kotlin/js/facade/Status.kt | 42 --------- .../kotlin/js/facade/TranslationResult.kt | 88 +++++++++++++++++++ 5 files changed, 112 insertions(+), 142 deletions(-) delete mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/facade/Status.kt create mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java index 4c1bf991ec2..05cd5c0869d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -23,7 +23,6 @@ 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 com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; @@ -55,10 +54,10 @@ import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS; import org.jetbrains.kotlin.js.config.Config; import org.jetbrains.kotlin.js.config.EcmaVersion; import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; +import org.jetbrains.kotlin.js.facade.K2JSTranslator; import org.jetbrains.kotlin.js.facade.MainCallParameters; -import org.jetbrains.kotlin.js.facade.Status; +import org.jetbrains.kotlin.js.facade.TranslationResult; import org.jetbrains.kotlin.psi.JetFile; -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.utils.PathUtil; import java.io.File; @@ -67,7 +66,6 @@ import java.util.List; import static org.jetbrains.kotlin.cli.common.ExitCode.COMPILATION_ERROR; import static org.jetbrains.kotlin.cli.common.ExitCode.OK; import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION; -import static org.jetbrains.kotlin.js.facade.K2JSTranslator.translateWithMainCallParameters; public class K2JSCompiler extends CLICompiler { @@ -159,22 +157,23 @@ public class K2JSCompiler extends CLICompiler { } MainCallParameters mainCallParameters = createMainCallParameters(arguments.main); - Status status; + TranslationResult translationResult; + K2JSTranslator translator = new K2JSTranslator(config); try { //noinspection unchecked - status = translateWithMainCallParameters(mainCallParameters, sourcesFiles, outputFile, outputPrefixFile, outputPostfixFile, - config, Consumer.EMPTY_CONSUMER); + translationResult = translator.translate(sourcesFiles, mainCallParameters); } catch (Exception e) { throw new RuntimeException(e); } - Diagnostics diagnostics = config.getTrace().getBindingContext().getDiagnostics(); - AnalyzerWithCompilerReport.reportDiagnostics(diagnostics, messageCollector); + AnalyzerWithCompilerReport.reportDiagnostics(translationResult.getDiagnostics(), messageCollector); - if (status.isFail()) return ExitCode.COMPILATION_ERROR; + if (!(translationResult instanceof TranslationResult.Success)) return ExitCode.COMPILATION_ERROR; + + TranslationResult.Success successResult = (TranslationResult.Success) translationResult; + OutputFileCollection outputFiles = successResult.getOutputFiles(outputFile, outputPrefixFile, outputPostfixFile); - OutputFileCollection outputFiles = status.getResult(); if (outputFile.isDirectory()) { messageCollector.report(CompilerMessageSeverity.ERROR, "Cannot open output file '" + outputFile.getPath() + "': is a directory", diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java index 3afc6dd55f8..0fe8e1647d2 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicTest.java @@ -39,8 +39,9 @@ import org.jetbrains.kotlin.js.config.Config; import org.jetbrains.kotlin.js.config.EcmaVersion; import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; import org.jetbrains.kotlin.js.config.LibrarySourcesConfigWithCaching; +import org.jetbrains.kotlin.js.facade.K2JSTranslator; import org.jetbrains.kotlin.js.facade.MainCallParameters; -import org.jetbrains.kotlin.js.facade.Status; +import org.jetbrains.kotlin.js.facade.TranslationResult; import org.jetbrains.kotlin.js.test.rhino.RhinoResultChecker; import org.jetbrains.kotlin.js.test.utils.JsTestUtils; import org.jetbrains.kotlin.js.translate.context.Namer; @@ -57,7 +58,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import static org.jetbrains.kotlin.js.facade.K2JSTranslator.translateWithMainCallParameters; import static org.jetbrains.kotlin.js.test.rhino.RhinoUtils.runRhinoTest; import static org.jetbrains.kotlin.js.test.utils.JsTestUtils.convertFileNameToDotJsFile; @@ -175,15 +175,18 @@ public abstract class BasicTest extends KotlinTestWithEnvironment { @NotNull MainCallParameters mainCallParameters, @NotNull Config config ) throws Exception { - Status status = translateWithMainCallParameters(mainCallParameters, jetFiles, outputFile, - getOutputPrefixFile(), getOutputPostfixFile(), - config, getConsumer()); + K2JSTranslator translator = new K2JSTranslator(config); + TranslationResult translationResult = translator.translate(jetFiles, mainCallParameters); - if (status.isFail()) return; + if (!(translationResult instanceof TranslationResult.Success)) return; + TranslationResult.Success successResult = (TranslationResult.Success) translationResult; + getConsumer().consume(successResult.getProgram()); + + OutputFileCollection outputFiles = successResult.getOutputFiles(outputFile, getOutputPrefixFile(), getOutputPostfixFile()); File outputDir = outputFile.getParentFile(); assert outputDir != null : "Parent file for output file should not be null, outputFilePath: " + outputFile.getPath(); - OutputUtilsPackage.writeAllTo(status.getResult(), outputDir); + OutputUtilsPackage.writeAllTo(outputFiles, outputDir); } protected File getOutputPostfixFile() { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java index 28bb460788e..7765f035a65 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/K2JSTranslator.java @@ -66,48 +66,6 @@ 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 Status translateWithMainCallParameters( - @NotNull MainCallParameters mainCall, - @NotNull List files, - @NotNull File outputFile, - @Nullable File outputPrefixFile, - @Nullable File outputPostfixFile, - @NotNull Config config, - @NotNull Consumer astConsumer // hack for tests - ) throws TranslationException, IOException { - K2JSTranslator translator = new K2JSTranslator(config); - TextOutputImpl output = new TextOutputImpl(); - SourceMapBuilder sourceMapBuilder = config.isSourcemap() ? new SourceMap3Builder(outputFile, output, new SourceMapBuilderConsumer()) : null; - 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); - - List sourceFiles = ContainerUtil.map(files, new Function() { - @Override - public File fun(JetFile file) { - VirtualFile virtualFile = file.getOriginalFile().getVirtualFile(); - if (virtualFile == null) return new File(file.getName()); - return VfsUtilCore.virtualToIoFile(virtualFile); - } - }); - - SimpleOutputFile jsFile = new SimpleOutputFile(sourceFiles, outputFile.getName(), prefix + programCode + postfix); - List outputFiles = new SmartList(jsFile); - - if (sourceMapBuilder != null) { - sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix)); - SimpleOutputFile sourceMapFile = new SimpleOutputFile(sourceFiles, sourceMapBuilder.getOutFile().getName(), sourceMapBuilder.build()); - outputFiles.add(sourceMapFile); - } - - OutputFileCollection outputFileCollection = new SimpleOutputFileCollection(outputFiles); - return Status.success(outputFileCollection); - } - @NotNull private final Config config; @@ -115,38 +73,10 @@ public final class K2JSTranslator { this.config = config; } - //NOTE: web demo related method - @SuppressWarnings("UnusedDeclaration") @NotNull - public Status translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { - JetFile file = JetPsiFactory(getProject()).createFile("test", programText); - 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 Status generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException { - return generateProgramCode(Collections.singletonList(file), mainCallParameters); - } - - @NotNull - 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 Status generateProgramCode( + public TranslationResult translate( @NotNull List files, - @NotNull MainCallParameters mainCallParameters, - @NotNull TextOutputImpl output, - @Nullable SourceMapBuilder sourceMapBuilder, - @NotNull Consumer astConsumer + @NotNull MainCallParameters mainCallParameters ) throws TranslationException { JsAnalysisResult analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, Predicates.alwaysTrue(), config); BindingTrace bindingTrace = analysisResult.getBindingTrace(); @@ -155,17 +85,9 @@ public final class K2JSTranslator { JsProgram program = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config); Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics(); - if (hasError(diagnostics)) return Status.fail(); + if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics); program = JsInliner.process(program); - program.accept(new JsSourceGenerationVisitor(output, sourceMapBuilder)); - astConsumer.consume(program); - - return Status.success(output.toString()); - } - - @NotNull - private Project getProject() { - return config.getProject(); + return new TranslationResult.Success(config, files, program, diagnostics); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/Status.kt b/js/js.translator/src/org/jetbrains/kotlin/js/facade/Status.kt deleted file mode 100644 index 520ef228a8c..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/Status.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010-2015 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.kotlin.js.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 - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt new file mode 100644 index 00000000000..1dcec41f037 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2015 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.kotlin.js.facade + +import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import com.google.dart.compiler.backend.js.ast.JsProgram +import kotlin.properties.Delegates +import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilder +import com.google.dart.compiler.util.TextOutputImpl +import org.jetbrains.kotlin.js.config.Config +import org.jetbrains.kotlin.backend.common.output.OutputFile +import org.jetbrains.kotlin.backend.common.output.OutputFileCollection +import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor +import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder +import com.google.dart.compiler.util.TextOutput +import java.io.File +import org.jetbrains.kotlin.utils.fileUtils.readTextOrEmpty +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.kotlin.psi.JetFile +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VfsUtilCore +import org.jetbrains.kotlin.backend.common.output.SimpleOutputFile +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection + +public abstract class TranslationResult protected (public val diagnostics: Diagnostics) { + + public class Fail(diagnostics: Diagnostics) : TranslationResult(diagnostics) + + public class Success( + private val config: Config, + private val files: List, + public val program: JsProgram, + diagnostics: Diagnostics + ) : TranslationResult(diagnostics) { + public fun getCode(): String = getCode(TextOutputImpl(), sourceMapBuilder = null) + + public fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection { + val output = TextOutputImpl() + val sourceMapBuilder = when { + config.isSourcemap() -> SourceMap3Builder(outputFile, output, SourceMapBuilderConsumer()) + else -> null + } + + val code = getCode(output, sourceMapBuilder) + val prefix = outputPrefixFile?.readTextOrEmpty() ?: "" + val postfix = outputPostfixFile?.readTextOrEmpty() ?: "" + val sourceFiles = files.map { + val virtualFile = it.getOriginalFile().getVirtualFile() + + when { + virtualFile == null -> File(it.getName()) + else -> VfsUtilCore.virtualToIoFile(virtualFile) + } + } + + val jsFile = SimpleOutputFile(sourceFiles, outputFile.getName(), prefix + code + postfix) + val outputFiles = arrayListOf(jsFile) + + if (sourceMapBuilder != null) { + sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix)) + val sourceMapFile = SimpleOutputFile(sourceFiles, sourceMapBuilder.getOutFile().getName(), sourceMapBuilder.build()) + outputFiles.add(sourceMapFile) + } + + return SimpleOutputFileCollection(outputFiles) + } + + private fun getCode(output: TextOutput, sourceMapBuilder: SourceMapBuilder?): String { + program.accept(JsSourceGenerationVisitor(output, sourceMapBuilder)) + return output.toString() + } + } +}