JS: reworking translator pipeline to generate multiple fragment each for source file
This commit is contained in:
@@ -100,7 +100,7 @@ var JsName.imported by MetadataProperty(default = false)
|
||||
|
||||
var JsFunction.coroutineMetadata: CoroutineMetadata? by MetadataProperty(default = null)
|
||||
|
||||
class CoroutineMetadata(
|
||||
data class CoroutineMetadata(
|
||||
val doResumeName: JsName,
|
||||
val stateName: JsName,
|
||||
val exceptionStateName: JsName,
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.facade;
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule;
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor;
|
||||
@@ -27,11 +25,8 @@ import org.jetbrains.kotlin.js.backend.ast.JsProgram;
|
||||
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.RemoveUnusedImportsKt;
|
||||
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
@@ -42,7 +37,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.DiagnosticUtils.hasError;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.ExpandIsCallsKt.expandIsCalls;
|
||||
|
||||
/**
|
||||
* An entry point of translator.
|
||||
@@ -80,11 +74,11 @@ public final class K2JSTranslator {
|
||||
ModuleDescriptor moduleDescriptor = analysisResult.getModuleDescriptor();
|
||||
Diagnostics diagnostics = bindingTrace.getBindingContext().getDiagnostics();
|
||||
|
||||
TranslationContext context = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
||||
JsProgram program = Translation.generateAst(bindingTrace, files, mainCallParameters, moduleDescriptor, config);
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||
|
||||
JsProgram program = JsInliner.process(context);
|
||||
//JsInliner.process(program);
|
||||
ResolveTemporaryNamesKt.resolveTemporaryNames(program);
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||
@@ -95,13 +89,13 @@ public final class K2JSTranslator {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||
|
||||
expandIsCalls(program, context);
|
||||
//expandIsCalls(program, context);
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
|
||||
List<String> importedModules = new ArrayList<>();
|
||||
for (JsImportedModule module : context.getImportedModules()) {
|
||||
/*for (JsImportedModule module : context.getImportedModules()) {
|
||||
importedModules.add(module.getExternalName());
|
||||
}
|
||||
}*/
|
||||
return new TranslationResult.Success(config, files, program, diagnostics, importedModules, moduleDescriptor,
|
||||
bindingTrace.getBindingContext());
|
||||
}
|
||||
|
||||
+4
-4
@@ -98,7 +98,7 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
|
||||
val getterBody: JsExpression = if (simpleProperty) {
|
||||
val accessToField = JsReturn(context.getInnerNameForDescriptor(declaration).makeRef())
|
||||
JsFunction(context.rootFunction.scope, JsBlock(accessToField), "$declaration getter")
|
||||
JsFunction(context.fragment.scope, JsBlock(accessToField), "$declaration getter")
|
||||
}
|
||||
else {
|
||||
context.getInnerNameForDescriptor(declaration.getter!!).makeRef()
|
||||
@@ -108,7 +108,7 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
if (declaration.isVar) {
|
||||
val setterBody: JsExpression = if (simpleProperty) {
|
||||
val statements = mutableListOf<JsStatement>()
|
||||
val function = JsFunction(context.rootFunction.scope, JsBlock(statements), "$declaration setter")
|
||||
val function = JsFunction(context.fragment.scope, JsBlock(statements), "$declaration setter")
|
||||
val valueName = function.scope.declareTemporaryName("value")
|
||||
function.parameters += JsParameter(valueName)
|
||||
statements += assignment(context.getInnerNameForDescriptor(declaration).makeRef(), valueName.makeRef()).makeStmt()
|
||||
@@ -125,11 +125,11 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
|
||||
private fun getLocalPackageReference(packageName: FqName): JsExpression {
|
||||
if (packageName.isRoot) {
|
||||
return context.rootFunction.scope.declareName(Namer.getRootPackageName()).makeRef()
|
||||
return context.fragment.scope.declareName(Namer.getRootPackageName()).makeRef()
|
||||
}
|
||||
var name = localPackageNames[packageName]
|
||||
if (name == null) {
|
||||
name = context.rootFunction.scope.declareTemporaryName("package$" + packageName.shortName().asString())
|
||||
name = context.fragment.scope.declareTemporaryName("package$" + packageName.shortName().asString())
|
||||
localPackageNames.put(packageName, name)
|
||||
|
||||
val parentRef = getLocalPackageReference(packageName.parent())
|
||||
|
||||
@@ -36,12 +36,11 @@ import org.jetbrains.kotlin.js.naming.NameSuggestion;
|
||||
import org.jetbrains.kotlin.js.naming.SuggestedName;
|
||||
import org.jetbrains.kotlin.js.translate.context.generator.Generator;
|
||||
import org.jetbrains.kotlin.js.translate.context.generator.Rule;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.InterfaceFunctionCopier;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.ClassModelGenerator;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
@@ -63,20 +62,12 @@ import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSuper
|
||||
* Aggregates all the static parts of the context.
|
||||
*/
|
||||
public final class StaticContext {
|
||||
|
||||
public static StaticContext generateStaticContext(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull JsConfig config,
|
||||
@NotNull ModuleDescriptor moduleDescriptor) {
|
||||
JsProgram program = new JsProgram();
|
||||
Namer namer = Namer.newInstance(program.getRootScope());
|
||||
JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope());
|
||||
return new StaticContext(program, rootFunction, bindingTrace, namer, program.getRootScope(), config, moduleDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsProgram program;
|
||||
|
||||
@NotNull
|
||||
private final JsProgramFragment fragment;
|
||||
|
||||
@NotNull
|
||||
private final BindingTrace bindingTrace;
|
||||
@NotNull
|
||||
@@ -132,51 +123,40 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private final JsScope rootPackageScope;
|
||||
|
||||
@NotNull
|
||||
private JsFunction rootFunction;
|
||||
|
||||
@NotNull
|
||||
private final List<JsStatement> declarationStatements = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
private final List<JsStatement> topLevelStatements = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
private final List<JsStatement> importStatements = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
private final DeclarationExporter exporter = new DeclarationExporter(this);
|
||||
|
||||
@NotNull
|
||||
private final Set<ClassDescriptor> classes = new LinkedHashSet<>();
|
||||
|
||||
@NotNull
|
||||
private final Map<FqName, JsScope> packageScopes = new HashMap<>();
|
||||
|
||||
//TODO: too many parameters in constructor
|
||||
private StaticContext(
|
||||
@NotNull JsProgram program,
|
||||
@NotNull JsFunction rootFunction,
|
||||
@NotNull
|
||||
private final ClassModelGenerator classModelGenerator;
|
||||
|
||||
public StaticContext(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull Namer namer,
|
||||
@NotNull JsScope rootScope,
|
||||
@NotNull JsConfig config,
|
||||
@NotNull ModuleDescriptor moduleDescriptor
|
||||
) {
|
||||
this.program = program;
|
||||
this.rootFunction = rootFunction;
|
||||
program = new JsProgram();
|
||||
JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope());
|
||||
fragment = new JsProgramFragment(rootFunction.getScope());
|
||||
|
||||
this.bindingTrace = bindingTrace;
|
||||
this.namer = namer;
|
||||
this.namer = Namer.newInstance(program.getRootScope());
|
||||
this.intrinsics = new Intrinsics(this);
|
||||
this.rootScope = rootScope;
|
||||
this.rootScope = fragment.getScope();
|
||||
this.config = config;
|
||||
this.currentModule = moduleDescriptor;
|
||||
this.rootFunction = rootFunction;
|
||||
rootPackageScope = new JsObjectScope(rootScope, "<root package>");
|
||||
|
||||
JsName kotlinName = rootScope.declareName(Namer.KOTLIN_NAME);
|
||||
importedModules.put(new JsImportedModuleKey(Namer.KOTLIN_LOWER_NAME, null),
|
||||
new JsImportedModule(Namer.KOTLIN_LOWER_NAME, kotlinName, null));
|
||||
|
||||
classModelGenerator = new ClassModelGenerator(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -184,6 +164,11 @@ public final class StaticContext {
|
||||
return program;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsProgramFragment getFragment() {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BindingTrace getBindingTrace() {
|
||||
return bindingTrace;
|
||||
@@ -408,7 +393,7 @@ public final class StaticContext {
|
||||
String baseName = NameSuggestion.sanitizeName(suggested.getNames().get(0));
|
||||
if (suggested.getDescriptor() instanceof LocalVariableDescriptor ||
|
||||
suggested.getDescriptor() instanceof ValueParameterDescriptor
|
||||
) {
|
||||
) {
|
||||
name = scope.declareTemporaryName(baseName);
|
||||
}
|
||||
else {
|
||||
@@ -474,7 +459,7 @@ public final class StaticContext {
|
||||
// since local scope inherited from global scope.
|
||||
// TODO: remove prefix when problem with scopes is solved
|
||||
|
||||
JsName result = rootFunction.getScope().declareTemporaryName(suggestedName);
|
||||
JsName result = fragment.getScope().declareTemporaryName(suggestedName);
|
||||
MetadataProperties.setImported(result, true);
|
||||
importStatements.add(JsAstUtils.newVar(result, declaration));
|
||||
return result;
|
||||
@@ -485,7 +470,7 @@ public final class StaticContext {
|
||||
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
|
||||
JsName name = module != currentModule ?
|
||||
importDeclaration(suggestedName, getQualifiedReference(descriptor)) :
|
||||
rootFunction.getScope().declareTemporaryName(suggestedName);
|
||||
fragment.getScope().declareTemporaryName(suggestedName);
|
||||
MetadataProperties.setDescriptor(name, descriptor);
|
||||
return name;
|
||||
}
|
||||
@@ -611,16 +596,16 @@ public final class StaticContext {
|
||||
}
|
||||
return getScopeForDescriptor(superclass).innerObjectScope("Scope for class " + descriptor.getName());
|
||||
};
|
||||
Rule<JsScope> generateNewScopesForPackageDescriptors = descriptor -> rootFunction.getScope();
|
||||
Rule<JsScope> generateNewScopesForPackageDescriptors = descriptor -> fragment.getScope();
|
||||
//TODO: never get there
|
||||
Rule<JsScope> generateInnerScopesForMembers =
|
||||
descriptor -> rootFunction.getScope().innerObjectScope("Scope for member " + descriptor.getName());
|
||||
descriptor -> fragment.getScope().innerObjectScope("Scope for member " + descriptor.getName());
|
||||
Rule<JsScope> createFunctionObjectsForCallableDescriptors = descriptor -> {
|
||||
if (!(descriptor instanceof CallableDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(rootFunction.getScope());
|
||||
JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(fragment.getScope());
|
||||
assert (!scopeToFunction.containsKey(correspondingFunction.getScope())) : "Scope to function value overridden for " + descriptor;
|
||||
scopeToFunction.put(correspondingFunction.getScope(), correspondingFunction);
|
||||
return correspondingFunction.getScope();
|
||||
@@ -712,23 +697,18 @@ public final class StaticContext {
|
||||
return deferredCallSites;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsFunction getRootFunction() {
|
||||
return rootFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsStatement> getTopLevelStatements() {
|
||||
return topLevelStatements;
|
||||
return fragment.getInitializerBlock().getStatements();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsStatement> getDeclarationStatements() {
|
||||
return declarationStatements;
|
||||
return fragment.getDeclarationBlock().getStatements();
|
||||
}
|
||||
|
||||
public void addClass(@NotNull ClassDescriptor classDescriptor) {
|
||||
classes.add(classDescriptor);
|
||||
fragment.getClasses().put(getInnerNameForDescriptor(classDescriptor), classModelGenerator.generateClassModel(classDescriptor));
|
||||
}
|
||||
|
||||
public void export(@NotNull MemberDescriptor descriptor, boolean force) {
|
||||
@@ -745,23 +725,23 @@ public final class StaticContext {
|
||||
return currentModule;
|
||||
}
|
||||
|
||||
public void postProcess() {
|
||||
/*public void postProcess() {
|
||||
addInterfaceDefaultMethods();
|
||||
rootFunction.getBody().getStatements().addAll(importStatements);
|
||||
addClassPrototypes();
|
||||
rootFunction.getBody().getStatements().addAll(declarationStatements);
|
||||
rootFunction.getBody().getStatements().addAll(exporter.getStatements());
|
||||
rootFunction.getBody().getStatements().addAll(topLevelStatements);
|
||||
}
|
||||
}*/
|
||||
|
||||
private void addClassPrototypes() {
|
||||
/*private void addClassPrototypes() {
|
||||
Set<ClassDescriptor> visited = new HashSet<>();
|
||||
for (ClassDescriptor cls : classes) {
|
||||
addClassPrototypes(cls, visited);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
private void addClassPrototypes(@NotNull ClassDescriptor cls, @NotNull Set<ClassDescriptor> visited) {
|
||||
/*private void addClassPrototypes(@NotNull ClassDescriptor cls, @NotNull Set<ClassDescriptor> visited) {
|
||||
if (!visited.add(cls)) return;
|
||||
if (DescriptorUtilsKt.getModule(cls) != currentModule) return;
|
||||
if (isNativeObject(cls) || isLibraryObject(cls)) return;
|
||||
@@ -789,19 +769,5 @@ public final class StaticContext {
|
||||
JsExpression constructorRef = new JsNameRef("constructor", prototype.deepCopy());
|
||||
statements.add(JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt());
|
||||
}
|
||||
}
|
||||
|
||||
private void addInterfaceDefaultMethods() {
|
||||
new InterfaceFunctionCopier(this).copyInterfaceFunctions(classes);
|
||||
}
|
||||
|
||||
public boolean isBuiltinModule() {
|
||||
for (ClassDescriptor cls : classes) {
|
||||
FqNameUnsafe fqn = DescriptorUtils.getFqName(cls);
|
||||
if ("kotlin.Enum".equals(fqn.asString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
+6
-6
@@ -69,9 +69,9 @@ public class TranslationContext {
|
||||
private final VariableDescriptor continuationParameterDescriptor;
|
||||
|
||||
@NotNull
|
||||
public static TranslationContext rootContext(@NotNull StaticContext staticContext, @NotNull JsFunction rootFunction) {
|
||||
JsBlock block = new JsBlock(staticContext.getTopLevelStatements());
|
||||
DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), block);
|
||||
public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
|
||||
DynamicContext rootDynamicContext = DynamicContext.rootContext(
|
||||
staticContext.getFragment().getScope(), staticContext.getFragment().getInitializerBlock());
|
||||
AliasingContext rootAliasingContext = AliasingContext.getCleanContext();
|
||||
return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null);
|
||||
}
|
||||
@@ -544,7 +544,7 @@ public class TranslationContext {
|
||||
if (result == null &&
|
||||
classOrConstructor instanceof ConstructorDescriptor &&
|
||||
((ConstructorDescriptor) classOrConstructor).isPrimary()
|
||||
) {
|
||||
) {
|
||||
result = staticContext.getClassOrConstructorClosure((ClassDescriptor) classOrConstructor.getContainingDeclaration());
|
||||
}
|
||||
return result;
|
||||
@@ -645,7 +645,7 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public JsName createGlobalName(@NotNull String suggestedName) {
|
||||
return staticContext.getRootFunction().getScope().declareTemporaryName(suggestedName);
|
||||
return staticContext.getFragment().getScope().declareTemporaryName(suggestedName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -655,7 +655,7 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public JsFunction createRootScopedFunction(@NotNull String description) {
|
||||
return new JsFunction(staticContext.getRootFunction().getScope(), new JsBlock(), description);
|
||||
return new JsFunction(staticContext.getFragment().getScope(), new JsBlock(), description);
|
||||
}
|
||||
|
||||
public void addClass(@NotNull ClassDescriptor classDescriptor) {
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsClassModel
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
|
||||
class ClassModelGenerator(val context: StaticContext) {
|
||||
fun generateClassModel(descriptor: ClassDescriptor): JsClassModel {
|
||||
val superName = descriptor.getSuperClassNotAny()?.let { context.getInnerNameForDescriptor(it) }
|
||||
val model = JsClassModel(context.getInnerNameForDescriptor(descriptor), superName)
|
||||
return model
|
||||
}
|
||||
}
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.translate.declaration
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsInvocation
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.prototypeOf
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.identity
|
||||
|
||||
class InterfaceFunctionCopier(val context: StaticContext) {
|
||||
private val classModels = mutableMapOf<ClassDescriptor, ClassModel>()
|
||||
|
||||
fun copyInterfaceFunctions(classes: Collection<ClassDescriptor>) {
|
||||
val orderedClasses = DFS.topologicalOrder(classes) { current -> DescriptorUtils.getSuperclassDescriptors(current) }.asReversed()
|
||||
|
||||
for (classDescriptor in orderedClasses) {
|
||||
addInterfaceDefaultMembers(classDescriptor, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addInterfaceDefaultMembers(descriptor: ClassDescriptor, context: StaticContext) {
|
||||
// optimization: don't do anything for native declarations
|
||||
if (isNativeObject(descriptor)) return
|
||||
|
||||
val classModel = ClassModel(descriptor)
|
||||
classModels[descriptor] = classModel
|
||||
|
||||
val members = descriptor.unsubstitutedMemberScope
|
||||
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
|
||||
.mapNotNull { it as? CallableMemberDescriptor }
|
||||
|
||||
for (member in members.filter { it.kind.isReal }) {
|
||||
val names = generateAllNames(member, context)
|
||||
val identifiers = names.map { it.ident }
|
||||
when (member) {
|
||||
is FunctionDescriptor -> {
|
||||
if (member.hasOrInheritsParametersWithDefaultValue()) {
|
||||
if (member.hasOwnParametersWithDefaultValue()) {
|
||||
classModel.copiedFunctions += identifiers.map { it }
|
||||
}
|
||||
if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedFunctions += identifiers.map { it + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX }
|
||||
}
|
||||
}
|
||||
else if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedFunctions += identifiers
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
if (member.modality != Modality.ABSTRACT) {
|
||||
classModel.copiedProperties += identifiers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (member in members.filterIsInstance<FunctionDescriptor>()) {
|
||||
moveDefaultFunction(member, context)
|
||||
}
|
||||
|
||||
for (member in members.filterIsInstance<FunctionDescriptor>()
|
||||
.filter { it.kind.isReal && it.hasOwnParametersWithDefaultValue() }) {
|
||||
val names = generateAllNames(member, context)
|
||||
val identifiers = names.map { it.ident }
|
||||
classModel.copiedFunctions += identifiers
|
||||
}
|
||||
|
||||
val superModels = DescriptorUtils.getSuperclassDescriptors(descriptor)
|
||||
.filter { it.kind == ClassKind.INTERFACE && !isNativeObject(it) }
|
||||
.map { classModels[it]!! }
|
||||
|
||||
for (superModel in superModels) {
|
||||
for (name in superModel.copiedFunctions) {
|
||||
if (classModel.copiedFunctions.add(name)) {
|
||||
addDefaultMethodFromInterface(name, name, superModel.descriptor, descriptor, context)
|
||||
}
|
||||
}
|
||||
for (name in superModel.copiedProperties) {
|
||||
if (classModel.copiedProperties.add(name)) {
|
||||
addDefaultPropertyFromInterface(name, superModel.descriptor, descriptor, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveDefaultFunction(function: FunctionDescriptor, context: StaticContext) {
|
||||
if (function.kind.isReal || function.modality == Modality.ABSTRACT) return
|
||||
|
||||
val overriddenWithDefaultArg = function.overriddenDescriptors
|
||||
.firstOrNull { it.hasOwnParametersWithDefaultValue() } ?: return
|
||||
|
||||
if (!DescriptorUtils.isInterface(overriddenWithDefaultArg.containingDeclaration)) return
|
||||
val fakeImplementation = function.overriddenDescriptors.first { it.modality != Modality.ABSTRACT }
|
||||
|
||||
val interfaceFunctionName = context.getNameForDescriptor(overriddenWithDefaultArg).ident
|
||||
val targetName = interfaceFunctionName + Namer.DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX
|
||||
val sourceName = context.getNameForDescriptor(fakeImplementation).ident
|
||||
|
||||
addDefaultMethodFromInterface(sourceName, targetName, fakeImplementation.containingDeclaration as ClassDescriptor,
|
||||
function.containingDeclaration as ClassDescriptor, context)
|
||||
|
||||
val overrideNames = generateAllNames(function, context).map { it.ident }
|
||||
val namesFromBaseClass = function.overriddenDescriptors
|
||||
.filter { !DescriptorUtils.isInterface(it.containingDeclaration) }
|
||||
.flatMap { generateAllNames(it, context).map { it.ident }.asIterable() }
|
||||
.distinct()
|
||||
|
||||
for (name in overrideNames.filter { it in namesFromBaseClass }) {
|
||||
addDefaultMethodFromInterface(interfaceFunctionName, name, overriddenWithDefaultArg.containingDeclaration as ClassDescriptor,
|
||||
function.containingDeclaration as ClassDescriptor, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDefaultMethodFromInterface(
|
||||
sourceName: String,
|
||||
targetName: String,
|
||||
sourceDescriptor: ClassDescriptor,
|
||||
targetDescriptor: ClassDescriptor,
|
||||
context: StaticContext
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val targetFunction = JsNameRef(targetName, targetPrototype)
|
||||
val sourceFunction = JsNameRef(sourceName, sourcePrototype)
|
||||
context.declarationStatements += JsAstUtils.assignment(targetFunction, sourceFunction).makeStmt()
|
||||
}
|
||||
|
||||
private fun addDefaultPropertyFromInterface(
|
||||
name: String,
|
||||
sourceDescriptor: ClassDescriptor,
|
||||
targetDescriptor: ClassDescriptor,
|
||||
context: StaticContext
|
||||
) {
|
||||
if (targetDescriptor.module != context.currentModule) return
|
||||
|
||||
val targetPrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(targetDescriptor), null))
|
||||
val sourcePrototype = prototypeOf(pureFqn(context.getInnerNameForDescriptor(sourceDescriptor), null))
|
||||
val nameLiteral = context.program.getStringLiteral(name)
|
||||
|
||||
val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), sourcePrototype, nameLiteral)
|
||||
val defineProperty = JsAstUtils.defineProperty(targetPrototype, name, getPropertyDescriptor, context.program)
|
||||
|
||||
context.declarationStatements += defineProperty.makeStmt()
|
||||
}
|
||||
|
||||
private fun generateAllNames(member: CallableMemberDescriptor, context: StaticContext): Sequence<JsName> {
|
||||
return (generateBridges(member) + member).map { context.getNameForDescriptor(it) }.distinctBy { it.ident }
|
||||
}
|
||||
|
||||
private fun generateBridges(member: CallableMemberDescriptor): Sequence<CallableMemberDescriptor> = when (member) {
|
||||
is FunctionDescriptor -> {
|
||||
generateBridgesForFunctionDescriptor(member, identity()) { false }
|
||||
.map { it.from }
|
||||
.asSequence()
|
||||
}
|
||||
is PropertyDescriptor -> generateBridgesForFunctionDescriptor(member.getter!!, identity()) { false }
|
||||
.map { it.from }
|
||||
.map { (it as PropertyAccessorDescriptor).correspondingProperty }
|
||||
.asSequence()
|
||||
else -> error("Expected either be function or property: $member")
|
||||
}
|
||||
|
||||
private class ClassModel(val descriptor: ClassDescriptor) {
|
||||
val copiedFunctions = mutableSetOf<String>()
|
||||
val copiedProperties = mutableSetOf<String>()
|
||||
}
|
||||
}
|
||||
-62
@@ -1,62 +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.translate.declaration;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.js.facade.exceptions.TranslationRuntimeException;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public final class PackageDeclarationTranslator extends AbstractTranslator {
|
||||
private final Iterable<KtFile> files;
|
||||
|
||||
public static void translateFiles(@NotNull Collection<KtFile> files, @NotNull TranslationContext context) {
|
||||
new PackageDeclarationTranslator(files, context).translate();
|
||||
}
|
||||
|
||||
private PackageDeclarationTranslator(@NotNull Iterable<KtFile> files, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
private void translate() {
|
||||
for (KtFile file : files) {
|
||||
FileDeclarationVisitor fileVisitor = new FileDeclarationVisitor(context());
|
||||
|
||||
try {
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (!AnnotationsUtils.isPredefinedObject(BindingUtils.getDescriptorForElement(bindingContext(), declaration))) {
|
||||
declaration.accept(fileVisitor, context());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TranslationRuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (RuntimeException | AssertionError e) {
|
||||
throw new TranslationRuntimeException(file, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.translate.general
|
||||
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||
import org.jetbrains.kotlin.js.inline.clean.resolveTemporaryNames
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||
|
||||
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName) {
|
||||
// Maps unique signature (see generateSignature) to names
|
||||
private val nameTable = mutableMapOf<String, JsName>()
|
||||
private val importBlock = JsGlobalBlock()
|
||||
private val declarationBlock = JsGlobalBlock()
|
||||
private val initializerBlock = JsGlobalBlock()
|
||||
private val exportBlock = JsGlobalBlock()
|
||||
|
||||
// Add declaration and initialization statements from program fragment to resulting single program
|
||||
fun addFragment(fragment: JsProgramFragment) {
|
||||
val nameMap = buildNameMap(fragment)
|
||||
nameMap.rename(fragment)
|
||||
|
||||
declarationBlock.statements += fragment.declarationBlock
|
||||
initializerBlock.statements += fragment.initializerBlock
|
||||
exportBlock.statements += fragment.exportBlock
|
||||
}
|
||||
|
||||
private fun Map<JsName, JsName>.rename(name: JsName): JsName = getOrElse(name) { name }
|
||||
|
||||
// Builds mapping to map names from different fragments into single name when they denote single declaration
|
||||
private fun buildNameMap(fragment: JsProgramFragment): Map<JsName, JsName> {
|
||||
val nameMap = mutableMapOf<JsName, JsName>()
|
||||
for (nameBinding in fragment.nameBindings) {
|
||||
nameMap[nameBinding.name] = nameTable.getOrPut(nameBinding.key) {
|
||||
fragment.scope.declareTemporaryName(nameBinding.name.ident).also { it.copyMetadataFrom(nameBinding.name) }
|
||||
}
|
||||
}
|
||||
fragment.scope.findName(Namer.getRootPackageName())?.let { nameMap[it] = internalModuleName }
|
||||
|
||||
return nameMap
|
||||
}
|
||||
|
||||
private fun Map<JsName, JsName>.rename(fragment: JsProgramFragment) {
|
||||
rename(fragment.declarationBlock)
|
||||
rename(fragment.exportBlock)
|
||||
rename(fragment.initializerBlock)
|
||||
}
|
||||
|
||||
private fun <T: JsNode> Map<JsName, JsName>.rename(node: T): T {
|
||||
node.accept(object : RecursiveJsVisitor() {
|
||||
override fun visitElement(node: JsNode) {
|
||||
super.visitElement(node)
|
||||
if (node is HasName) {
|
||||
node.name = node.name?.let { name -> rename(name) }
|
||||
}
|
||||
if (node is JsFunction) {
|
||||
val coroutineMetadata = node.coroutineMetadata
|
||||
if (coroutineMetadata != null) {
|
||||
node.coroutineMetadata = coroutineMetadata.copy(
|
||||
baseClassRef = rename(coroutineMetadata.baseClassRef),
|
||||
suspendObjectRef = rename(coroutineMetadata.suspendObjectRef)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return node
|
||||
}
|
||||
|
||||
// Adds different boilerplate code (like imports, class prototypes, etc) to resulting program.
|
||||
fun merge() {
|
||||
rootFunction.body.statements.apply {
|
||||
this += importBlock.statements
|
||||
this += declarationBlock.statements
|
||||
this += initializerBlock.statements
|
||||
}
|
||||
rootFunction.body.resolveTemporaryNames()
|
||||
}
|
||||
}
|
||||
@@ -33,18 +33,17 @@ import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext;
|
||||
import org.jetbrains.kotlin.js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.PackageDeclarationTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.declaration.FileDeclarationVisitor;
|
||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor;
|
||||
import org.jetbrains.kotlin.js.translate.expression.PatternTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSTestGenerator;
|
||||
import org.jetbrains.kotlin.js.translate.test.JSTester;
|
||||
import org.jetbrains.kotlin.js.translate.test.QUnitTester;
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.mutator.AssignToExpressionMutator;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction;
|
||||
import org.jetbrains.kotlin.psi.KtUnaryExpression;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
@@ -71,6 +70,7 @@ import static org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMuta
|
||||
* Goal is to simplify interaction between translators.
|
||||
*/
|
||||
public final class Translation {
|
||||
private static final String ENUM_SIGNATURE = "kotlin$Enum";
|
||||
|
||||
private Translation() {
|
||||
}
|
||||
@@ -234,7 +234,7 @@ public final class Translation {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static TranslationContext generateAst(
|
||||
public static JsProgram generateAst(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull Collection<KtFile> files,
|
||||
@NotNull MainCallParameters mainCallParameters,
|
||||
@@ -253,38 +253,49 @@ public final class Translation {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TranslationContext doGenerateAst(
|
||||
private static JsProgram doGenerateAst(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull Collection<KtFile> files,
|
||||
@NotNull MainCallParameters mainCallParameters,
|
||||
@NotNull ModuleDescriptor moduleDescriptor,
|
||||
@NotNull JsConfig config
|
||||
) {
|
||||
StaticContext staticContext = StaticContext.generateStaticContext(bindingTrace, config, moduleDescriptor);
|
||||
JsProgram program = staticContext.getProgram();
|
||||
JsName rootPackageName = program.getRootScope().declareName(Namer.getRootPackageName());
|
||||
JsProgram program = new JsProgram();
|
||||
JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function");
|
||||
Merger merger = new Merger(rootFunction);
|
||||
|
||||
List<JsProgramFragment> fragments = new ArrayList<JsProgramFragment>();
|
||||
for (KtFile file : files) {
|
||||
StaticContext staticContext = new StaticContext(bindingTrace, config, moduleDescriptor);
|
||||
TranslationContext context = TranslationContext.rootContext(staticContext);
|
||||
translateFile(context, file);
|
||||
fragments.add(staticContext.getFragment());
|
||||
merger.addFragment(staticContext.getFragment());
|
||||
}
|
||||
|
||||
merger.merge();
|
||||
|
||||
JsFunction rootFunction = staticContext.getRootFunction();
|
||||
JsBlock rootBlock = rootFunction.getBody();
|
||||
|
||||
List<JsStatement> statements = rootBlock.getStatements();
|
||||
|
||||
program.getScope().declareName("_");
|
||||
|
||||
TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction);
|
||||
PackageDeclarationTranslator.translateFiles(files, context);
|
||||
staticContext.postProcess();
|
||||
//staticContext.postProcess();
|
||||
statements.add(0, program.getStringLiteral("use strict").makeStmt());
|
||||
if (!staticContext.isBuiltinModule()) {
|
||||
defineModule(context, statements, config.getModuleId());
|
||||
if (!isBuiltinModule(fragments)) {
|
||||
defineModule(program, statements, config.getModuleId());
|
||||
}
|
||||
|
||||
mayBeGenerateTests(files, rootBlock, context);
|
||||
//mayBeGenerateTests(files, rootBlock, context);
|
||||
JsName rootPackageName = program.getScope().declareName(Namer.getRootPackageName());
|
||||
rootFunction.getParameters().add(new JsParameter((rootPackageName)));
|
||||
|
||||
// Invoke function passing modules as arguments
|
||||
// This should help minifier tool to recognize references to these modules as local variables and make them shorter.
|
||||
List<JsImportedModule> importedModuleList = new ArrayList<>();
|
||||
|
||||
/*
|
||||
for (JsImportedModule importedModule : staticContext.getImportedModules()) {
|
||||
rootFunction.getParameters().add(new JsParameter(importedModule.getInternalName()));
|
||||
importedModuleList.add(importedModule);
|
||||
@@ -296,6 +307,7 @@ public final class Translation {
|
||||
statements.add(statement);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
statements.add(new JsReturn(rootPackageName.makeRef()));
|
||||
|
||||
@@ -303,13 +315,46 @@ public final class Translation {
|
||||
block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program,
|
||||
config.getModuleKind()));
|
||||
|
||||
return context;
|
||||
return program;
|
||||
}
|
||||
|
||||
private static void defineModule(@NotNull TranslationContext context, @NotNull List<JsStatement> statements, @NotNull String moduleId) {
|
||||
JsName rootPackageName = context.scope().findName(Namer.getRootPackageName());
|
||||
private static boolean isBuiltinModule(@NotNull List<JsProgramFragment> fragments) {
|
||||
for (JsProgramFragment fragment : fragments) {
|
||||
for (JsNameBinding nameBinding : fragment.getNameBindings()) {
|
||||
if (nameBinding.getKey().equals(ENUM_SIGNATURE) && !fragment.getImports().containsKey(ENUM_SIGNATURE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void translateFile(@NotNull TranslationContext context, @NotNull KtFile file) {
|
||||
FileDeclarationVisitor fileVisitor = new FileDeclarationVisitor(context);
|
||||
|
||||
try {
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (!AnnotationsUtils.isPredefinedObject(BindingUtils.getDescriptorForElement(context.bindingContext(), declaration))) {
|
||||
declaration.accept(fileVisitor, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TranslationRuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw new TranslationRuntimeException(file, e);
|
||||
}
|
||||
catch (AssertionError e) {
|
||||
throw new TranslationRuntimeException(file, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void defineModule(@NotNull JsProgram program, @NotNull List<JsStatement> statements, @NotNull String moduleId) {
|
||||
JsName rootPackageName = program.getScope().findName(Namer.getRootPackageName());
|
||||
if (rootPackageName != null) {
|
||||
statements.add(new JsInvocation(context.namer().kotlin("defineModule"), context.program().getStringLiteral(moduleId),
|
||||
Namer namer = Namer.newInstance(program.getScope());
|
||||
statements.add(new JsInvocation(namer.kotlin("defineModule"), program.getStringLiteral(moduleId),
|
||||
rootPackageName.makeRef()).makeStmt());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.translate.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.naming.encodeSignature
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
// Unfortunately, our descriptor serializer can't serialize references to descriptors.
|
||||
// We have to serialize entire class or package to serialize function or property.
|
||||
// In case of declarations from external modules we end up with duplication of significant metadata.
|
||||
|
||||
// What we really need these descriptors is to determine which names from different fragments point to one declarations,
|
||||
// so that merger could turn these names into one name. Actually, we need a way to get unique identifier for every
|
||||
// declaration.
|
||||
|
||||
// This code does not generate unique identifiers, it's possible to pick two declarations with same strings. However,
|
||||
// it's hard to do it unintentionally.
|
||||
fun generateSignature(descriptor: DeclarationDescriptor): String? {
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) return null
|
||||
if (descriptor is DeclarationDescriptorWithVisibility && descriptor.visibility == Visibilities.PRIVATE &&
|
||||
!AnnotationsUtils.isNativeObject(descriptor) && !AnnotationsUtils.isLibraryObject(descriptor)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
return when (descriptor) {
|
||||
is CallableDescriptor -> {
|
||||
val parent = generateSignature(descriptor.containingDeclaration) ?: return null
|
||||
if (descriptor !is VariableAccessorDescriptor && descriptor !is ConstructorDescriptor && descriptor.name.isSpecial) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Make distinction between functions with zero parameters and properties
|
||||
val separator = if (descriptor is FunctionDescriptor) "#" else "!"
|
||||
|
||||
parent + separator + escape(descriptor.name.asString()) + "|" + encodeSignature(descriptor)
|
||||
}
|
||||
is PackageFragmentDescriptor -> {
|
||||
if (descriptor.fqName.isRoot) "" else escape(descriptor.fqName.pathSegments().map { escape(it.identifier) }.joinToString("."))
|
||||
}
|
||||
is ClassDescriptor -> {
|
||||
val parent = generateSignature(descriptor.containingDeclaration) ?: return null
|
||||
if (descriptor.name.isSpecial) return null
|
||||
parent + "$" + escape(descriptor.name.asString())
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun escape(s: String): String {
|
||||
val sb = StringBuilder()
|
||||
for (c in s) {
|
||||
val escapedChar = when (c) {
|
||||
'\\', '"', '.', '$', '#', '!', '<', '>', '|', '+', '-', ':', '*', '?' -> "\\$c"
|
||||
else -> c.toString()
|
||||
}
|
||||
sb.append(escapedChar)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
Reference in New Issue
Block a user