JS: convert K2JSTranslator to Kotlin
This commit is contained in:
@@ -1,210 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 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 com.intellij.openapi.vfs.VfsUtilCore;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
|
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeysKt;
|
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
|
|
||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer;
|
|
||||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS;
|
|
||||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgramFragment;
|
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys;
|
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
|
||||||
import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer;
|
|
||||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
|
||||||
import org.jetbrains.kotlin.js.inline.JsInliner;
|
|
||||||
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation;
|
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveDuplicateImportsKt;
|
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
|
||||||
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
|
||||||
import org.jetbrains.kotlin.js.translate.general.AstGenerationResult;
|
|
||||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
|
||||||
import org.jetbrains.kotlin.js.translate.utils.ExpandIsCallsKt;
|
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf;
|
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion;
|
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
|
||||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
|
|
||||||
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
|
|
||||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializer;
|
|
||||||
import org.jetbrains.kotlin.utils.JsMetadataVersion;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.DiagnosticUtils.hasError;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An entry point of translator.
|
|
||||||
*/
|
|
||||||
public final class K2JSTranslator {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final JsConfig config;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private final IncrementalResultsConsumer incrementalResults;
|
|
||||||
|
|
||||||
public K2JSTranslator(@NotNull JsConfig config) {
|
|
||||||
this.config = config;
|
|
||||||
this.incrementalResults = config.getConfiguration().get(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TranslationResult translate(
|
|
||||||
@NotNull JsConfig.Reporter reporter,
|
|
||||||
@NotNull List<KtFile> files,
|
|
||||||
@NotNull MainCallParameters mainCallParameters
|
|
||||||
) throws TranslationException {
|
|
||||||
return translate(reporter, files, mainCallParameters, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TranslationResult translate(
|
|
||||||
@NotNull JsConfig.Reporter reporter,
|
|
||||||
@NotNull List<KtFile> files,
|
|
||||||
@NotNull MainCallParameters mainCallParameters,
|
|
||||||
@Nullable JsAnalysisResult analysisResult
|
|
||||||
) throws TranslationException {
|
|
||||||
List<TranslationUnit> units = new ArrayList<>();
|
|
||||||
for (KtFile file : files) {
|
|
||||||
units.add(new TranslationUnit.SourceFile(file));
|
|
||||||
}
|
|
||||||
return translateUnits(reporter, units, mainCallParameters, analysisResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TranslationResult translateUnits(
|
|
||||||
@NotNull JsConfig.Reporter reporter,
|
|
||||||
@NotNull List<TranslationUnit> units,
|
|
||||||
@NotNull MainCallParameters mainCallParameters
|
|
||||||
) throws TranslationException {
|
|
||||||
return translateUnits(reporter, units, mainCallParameters, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TranslationResult translateUnits(
|
|
||||||
@NotNull JsConfig.Reporter reporter,
|
|
||||||
@NotNull List<TranslationUnit> units,
|
|
||||||
@NotNull MainCallParameters mainCallParameters,
|
|
||||||
@Nullable JsAnalysisResult analysisResult
|
|
||||||
) throws TranslationException {
|
|
||||||
List<KtFile> files = new ArrayList<>();
|
|
||||||
for (TranslationUnit unit : units) {
|
|
||||||
if (unit instanceof TranslationUnit.SourceFile) {
|
|
||||||
files.add(((TranslationUnit.SourceFile) unit).getFile());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (analysisResult == null) {
|
|
||||||
analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, config);
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
}
|
|
||||||
|
|
||||||
BindingTrace bindingTrace = analysisResult.getBindingTrace();
|
|
||||||
TopDownAnalyzerFacadeForJS.checkForErrors(files, bindingTrace.getBindingContext());
|
|
||||||
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
|
||||||
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
|
||||||
|
|
||||||
SourceFilePathResolver pathResolver = SourceFilePathResolver.create(config);
|
|
||||||
|
|
||||||
AstGenerationResult translationResult = Translation.generateAst(
|
|
||||||
bindingTrace, units, mainCallParameters, moduleDescriptor, config, pathResolver);
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
|
||||||
|
|
||||||
List<JsProgramFragment> newFragments = new ArrayList<>(translationResult.getNewFragments());
|
|
||||||
List<JsProgramFragment> allFragments = new ArrayList<>(translationResult.getFragments());
|
|
||||||
|
|
||||||
JsInliner.process(reporter, config, analysisResult.getBindingTrace(), translationResult.getInnerModuleName(),
|
|
||||||
allFragments, newFragments, translationResult.getImportStatements());
|
|
||||||
|
|
||||||
LabeledBlockToDoWhileTransformation.INSTANCE.apply(newFragments);
|
|
||||||
|
|
||||||
CoroutineTransformer coroutineTransformer = new CoroutineTransformer();
|
|
||||||
for (JsProgramFragment fragment : newFragments) {
|
|
||||||
coroutineTransformer.accept(fragment.getDeclarationBlock());
|
|
||||||
coroutineTransformer.accept(fragment.getInitializerBlock());
|
|
||||||
}
|
|
||||||
RemoveUnusedImportsKt.removeUnusedImports(translationResult.getProgram());
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
|
||||||
|
|
||||||
ExpandIsCallsKt.expandIsCalls(newFragments);
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
JsAstSerializer serializer = new JsAstSerializer(file -> {
|
|
||||||
try {
|
|
||||||
return pathResolver.getPathRelativeToSourceRoots(file);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException("IO error occurred resolving path to source file", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (incrementalResults != null) {
|
|
||||||
KotlinJavascriptSerializationUtil serializationUtil = KotlinJavascriptSerializationUtil.INSTANCE;
|
|
||||||
|
|
||||||
for (KtFile file : files) {
|
|
||||||
JsProgramFragment fragment = translationResult.getFragmentMap().get(file);
|
|
||||||
assert fragment != null : "Could not find AST for file: " + file;
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
|
||||||
serializer.serialize(fragment, output);
|
|
||||||
byte[] binaryAst = output.toByteArray();
|
|
||||||
|
|
||||||
List<DeclarationDescriptor> scope = translationResult.getFileMemberScopes().get(file);
|
|
||||||
assert scope != null : "Could not find descriptors for file: " + file;
|
|
||||||
BinaryVersion metadataVersion = config.getConfiguration().get(CommonConfigurationKeys.METADATA_VERSION);
|
|
||||||
ProtoBuf.PackageFragment packagePart = serializationUtil.serializeDescriptors(
|
|
||||||
bindingTrace.getBindingContext(), moduleDescriptor, scope, file.getPackageFqName(),
|
|
||||||
CommonConfigurationKeysKt.getLanguageVersionSettings(config.getConfiguration()),
|
|
||||||
metadataVersion != null ? metadataVersion : JsMetadataVersion.INSTANCE
|
|
||||||
);
|
|
||||||
|
|
||||||
File ioFile = VfsUtilCore.virtualToIoFile(file.getVirtualFile());
|
|
||||||
incrementalResults.processPackagePart(ioFile, packagePart.toByteArray(), binaryAst);
|
|
||||||
}
|
|
||||||
|
|
||||||
LanguageVersionSettings settings = CommonConfigurationKeysKt.getLanguageVersionSettings(config.getConfiguration());
|
|
||||||
incrementalResults.processHeader(serializationUtil.serializeHeader(moduleDescriptor, null, settings).toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveDuplicateImportsKt.removeDuplicateImports(translationResult.getProgram());
|
|
||||||
ResolveTemporaryNamesKt.resolveTemporaryNames(translationResult.getProgram());
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
|
||||||
|
|
||||||
List<String> importedModules = new ArrayList<>();
|
|
||||||
for (JsImportedModule module : translationResult.getImportedModuleList()) {
|
|
||||||
importedModules.add(module.getExternalName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TranslationResult.Success(config, files, translationResult.getProgram(), diagnostics, importedModules,
|
|
||||||
moduleDescriptor, bindingTrace.getBindingContext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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 com.intellij.openapi.vfs.VfsUtilCore
|
||||||
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.config.*
|
||||||
|
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||||
|
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||||
|
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||||
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
|
import org.jetbrains.kotlin.js.coroutine.CoroutineTransformer
|
||||||
|
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException
|
||||||
|
import org.jetbrains.kotlin.js.inline.JsInliner
|
||||||
|
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation
|
||||||
|
import org.jetbrains.kotlin.js.inline.clean.*
|
||||||
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
||||||
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.*
|
||||||
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
|
||||||
|
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializer
|
||||||
|
import org.jetbrains.kotlin.utils.JsMetadataVersion
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils.hasError
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry point of translator.
|
||||||
|
*/
|
||||||
|
class K2JSTranslator(private val config: JsConfig) {
|
||||||
|
|
||||||
|
private val incrementalResults = config.configuration.get(JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER)
|
||||||
|
|
||||||
|
@Throws(TranslationException::class)
|
||||||
|
@JvmOverloads
|
||||||
|
fun translate(
|
||||||
|
reporter: JsConfig.Reporter,
|
||||||
|
files: List<KtFile>,
|
||||||
|
mainCallParameters: MainCallParameters,
|
||||||
|
analysisResult: JsAnalysisResult? = null
|
||||||
|
): TranslationResult {
|
||||||
|
val units = ArrayList<TranslationUnit>()
|
||||||
|
for (file in files) {
|
||||||
|
units.add(TranslationUnit.SourceFile(file))
|
||||||
|
}
|
||||||
|
return translateUnits(reporter, units, mainCallParameters, analysisResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(TranslationException::class)
|
||||||
|
@JvmOverloads
|
||||||
|
fun translateUnits(
|
||||||
|
reporter: JsConfig.Reporter,
|
||||||
|
units: List<TranslationUnit>,
|
||||||
|
mainCallParameters: MainCallParameters,
|
||||||
|
analysisResult: JsAnalysisResult? = null
|
||||||
|
): TranslationResult {
|
||||||
|
var analysisResult = analysisResult
|
||||||
|
val files = ArrayList<KtFile>()
|
||||||
|
for (unit in units) {
|
||||||
|
if (unit is TranslationUnit.SourceFile) {
|
||||||
|
files.add(unit.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (analysisResult == null) {
|
||||||
|
analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, config)
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bindingTrace = analysisResult.bindingTrace
|
||||||
|
TopDownAnalyzerFacadeForJS.checkForErrors(files, bindingTrace.bindingContext)
|
||||||
|
val moduleDescriptor = analysisResult.moduleDescriptor
|
||||||
|
val diagnostics = bindingTrace.bindingContext.diagnostics
|
||||||
|
|
||||||
|
val pathResolver = SourceFilePathResolver.create(config)
|
||||||
|
|
||||||
|
val translationResult = Translation.generateAst(
|
||||||
|
bindingTrace, units, mainCallParameters, moduleDescriptor, config, pathResolver
|
||||||
|
)
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
if (hasError(diagnostics)) return TranslationResult.Fail(diagnostics)
|
||||||
|
|
||||||
|
val newFragments = ArrayList(translationResult.newFragments)
|
||||||
|
val allFragments = ArrayList(translationResult.fragments)
|
||||||
|
|
||||||
|
JsInliner.process(
|
||||||
|
reporter, config, analysisResult.bindingTrace, translationResult.innerModuleName,
|
||||||
|
allFragments, newFragments, translationResult.importStatements
|
||||||
|
)
|
||||||
|
|
||||||
|
LabeledBlockToDoWhileTransformation.apply(newFragments)
|
||||||
|
|
||||||
|
val coroutineTransformer = CoroutineTransformer()
|
||||||
|
for (fragment in newFragments) {
|
||||||
|
coroutineTransformer.accept(fragment.declarationBlock)
|
||||||
|
coroutineTransformer.accept(fragment.initializerBlock)
|
||||||
|
}
|
||||||
|
removeUnusedImports(translationResult.program)
|
||||||
|
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
if (hasError(diagnostics)) return TranslationResult.Fail(diagnostics)
|
||||||
|
|
||||||
|
expandIsCalls(newFragments)
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
val serializer = JsAstSerializer { file ->
|
||||||
|
try {
|
||||||
|
pathResolver.getPathRelativeToSourceRoots(file)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw RuntimeException("IO error occurred resolving path to source file", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incrementalResults != null) {
|
||||||
|
val serializationUtil = KotlinJavascriptSerializationUtil
|
||||||
|
|
||||||
|
for (file in files) {
|
||||||
|
val fragment = translationResult.fragmentMap[file] ?: error("Could not find AST for file: $file")
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
serializer.serialize(fragment, output)
|
||||||
|
val binaryAst = output.toByteArray()
|
||||||
|
|
||||||
|
val scope = translationResult.fileMemberScopes[file] ?: error("Could not find descriptors for file: $file")
|
||||||
|
val metadataVersion = config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)
|
||||||
|
val packagePart = serializationUtil.serializeDescriptors(
|
||||||
|
bindingTrace.bindingContext, moduleDescriptor, scope, file.packageFqName,
|
||||||
|
config.configuration.languageVersionSettings,
|
||||||
|
metadataVersion ?: JsMetadataVersion.INSTANCE
|
||||||
|
)
|
||||||
|
|
||||||
|
val ioFile = VfsUtilCore.virtualToIoFile(file.virtualFile)
|
||||||
|
incrementalResults.processPackagePart(ioFile, packagePart.toByteArray(), binaryAst)
|
||||||
|
}
|
||||||
|
|
||||||
|
val settings = config.configuration.languageVersionSettings
|
||||||
|
incrementalResults.processHeader(serializationUtil.serializeHeader(moduleDescriptor, null, settings).toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
removeDuplicateImports(translationResult.program)
|
||||||
|
translationResult.program.resolveTemporaryNames()
|
||||||
|
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
if (hasError(diagnostics)) return TranslationResult.Fail(diagnostics)
|
||||||
|
|
||||||
|
val importedModules = ArrayList<String>()
|
||||||
|
for (module in translationResult.importedModuleList) {
|
||||||
|
importedModules.add(module.externalName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return TranslationResult.Success(
|
||||||
|
config, files, translationResult.program, diagnostics, importedModules,
|
||||||
|
moduleDescriptor, bindingTrace.bindingContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user