JS: added TranslationResult

This commit is contained in:
Alexey Tsvetkov
2015-01-18 22:14:53 +03:00
parent aa5f237154
commit f5eb39e1f1
5 changed files with 112 additions and 142 deletions
@@ -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<K2JSCompilerArguments> {
@@ -159,22 +157,23 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
}
MainCallParameters mainCallParameters = createMainCallParameters(arguments.main);
Status<OutputFileCollection> 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",
@@ -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<OutputFileCollection> 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() {
@@ -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<OutputFileCollection> translateWithMainCallParameters(
@NotNull MainCallParameters mainCall,
@NotNull List<JetFile> files,
@NotNull File outputFile,
@Nullable File outputPrefixFile,
@Nullable File outputPostfixFile,
@NotNull Config config,
@NotNull Consumer<JsNode> 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<String> 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<File> sourceFiles = ContainerUtil.map(files, new Function<JetFile, File>() {
@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<SimpleOutputFile> outputFiles = new SmartList<SimpleOutputFile>(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<String> translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException {
JetFile file = JetPsiFactory(getProject()).createFile("test", programText);
Status<String> 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<String> generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException {
return generateProgramCode(Collections.singletonList(file), mainCallParameters);
}
@NotNull
public Status<String> generateProgramCode(@NotNull List<JetFile> files, @NotNull MainCallParameters mainCallParameters)
throws TranslationException {
//noinspection unchecked
return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null, Consumer.EMPTY_CONSUMER);
}
@NotNull
public Status<String> generateProgramCode(
public TranslationResult translate(
@NotNull List<JetFile> files,
@NotNull MainCallParameters mainCallParameters,
@NotNull TextOutputImpl output,
@Nullable SourceMapBuilder sourceMapBuilder,
@NotNull Consumer<JsNode> astConsumer
@NotNull MainCallParameters mainCallParameters
) throws TranslationException {
JsAnalysisResult analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, Predicates.<PsiFile>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);
}
}
@@ -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<out T> private (private val _result: T, private val type: Status.Type) {
class object {
platformStatic fun fail<T>(): Status<T> = Status<T>(null, Type.Fail)
platformStatic fun success<T>(value: T): Status<T> = 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
}
}
@@ -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<JetFile>,
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()
}
}
}