JS: support imports in new pipeline

This commit is contained in:
Alexey Andreev
2017-02-10 18:34:14 +03:00
parent 6711db86ee
commit 108fcba885
5 changed files with 50 additions and 20 deletions
@@ -40,6 +40,7 @@ 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.js.translate.utils.SignatureUtilsKt;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
@@ -115,6 +116,8 @@ public final class StaticContext {
@NotNull
private final Map<DeclarationDescriptor, JsExpression> fqnCache = new HashMap<>();
private final Map<DeclarationDescriptor, String> tagCache = new HashMap<>();
@NotNull
private final Map<JsImportedModuleKey, JsImportedModule> importedModules = new LinkedHashMap<>();
@@ -123,9 +126,6 @@ public final class StaticContext {
@NotNull
private final JsScope rootPackageScope;
@NotNull
private final List<JsStatement> importStatements = new ArrayList<>();
@NotNull
private final DeclarationExporter exporter = new DeclarationExporter(this);
@@ -220,6 +220,19 @@ public final class StaticContext {
return (JsNameRef) getQualifiedExpression(descriptor);
}
@Nullable
private String getTag(@NotNull DeclarationDescriptor descriptor) {
String tag;
if (!tagCache.containsKey(descriptor)) {
tag = SignatureUtilsKt.generateSignature(descriptor);
tagCache.put(descriptor, tag);
}
else {
tag = tagCache.get(descriptor);
}
return tag;
}
@NotNull
private JsExpression getQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
JsExpression fqn = fqnCache.computeIfAbsent(descriptor, this::buildQualifiedExpression);
@@ -451,7 +464,7 @@ public final class StaticContext {
}
@NotNull
public JsName importDeclaration(@NotNull String suggestedName, @NotNull JsExpression declaration) {
public JsName importDeclaration(@NotNull String suggestedName, @NotNull String tag, @NotNull JsExpression declaration) {
// Adding prefix is a workaround for a problem with scopes.
// Consider we declare name `foo` in functions's local scope, then call top-level function `foo`
// from another module. It's imported into global scope under name `foo`. If we could somehow
@@ -461,16 +474,25 @@ public final class StaticContext {
JsName result = fragment.getScope().declareTemporaryName(suggestedName);
MetadataProperties.setImported(result, true);
importStatements.add(JsAstUtils.newVar(result, declaration));
fragment.getImports().put(tag, declaration);
return result;
}
@NotNull
private JsName localOrImportedName(@NotNull DeclarationDescriptor descriptor, @NotNull String suggestedName) {
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
JsName name = module != currentModule ?
importDeclaration(suggestedName, getQualifiedReference(descriptor)) :
fragment.getScope().declareTemporaryName(suggestedName);
JsName name;
String tag = getTag(descriptor);
if (module != currentModule) {
assert tag != null : "Can't import declaration without fqname: " + descriptor;
name = importDeclaration(suggestedName, tag, getQualifiedReference(descriptor));
}
else {
name = fragment.getScope().declareTemporaryName(suggestedName);
}
if (tag != null) {
fragment.getNameBindings().add(new JsNameBinding(tag, name));
}
MetadataProperties.setDescriptor(name, descriptor);
return name;
}
@@ -672,14 +694,13 @@ public final class StaticContext {
return suggestedName.getNames().get(0);
}
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
private static void applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
if (descriptor instanceof FunctionDescriptor ||
descriptor instanceof PackageFragmentDescriptor ||
descriptor instanceof ClassDescriptor
) {
) {
MetadataProperties.setSideEffects(expression, SideEffectKind.PURE);
}
return expression;
}
public void putClassOrConstructorClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
@@ -20,6 +20,7 @@ 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
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
class Merger(private val rootFunction: JsFunction, val internalModuleName: JsName) {
// Maps unique signature (see generateSignature) to names
@@ -28,12 +29,20 @@ class Merger(private val rootFunction: JsFunction, val internalModuleName: JsNam
private val declarationBlock = JsGlobalBlock()
private val initializerBlock = JsGlobalBlock()
private val exportBlock = JsGlobalBlock()
private val declaredImports = mutableSetOf<String>()
// Add declaration and initialization statements from program fragment to resulting single program
fun addFragment(fragment: JsProgramFragment) {
val nameMap = buildNameMap(fragment)
nameMap.rename(fragment)
for ((key, importExpr) in fragment.imports) {
if (declaredImports.add(key)) {
val name = nameTable[key]!!
importBlock.statements += JsAstUtils.newVar(nameMap.rename(name), nameMap.rename(importExpr))
}
}
declarationBlock.statements += fragment.declarationBlock
initializerBlock.statements += fragment.initializerBlock
exportBlock.statements += fragment.exportBlock
@@ -262,7 +262,8 @@ public final class Translation {
) {
JsProgram program = new JsProgram();
JsFunction rootFunction = new JsFunction(program.getRootScope(), new JsBlock(), "root function");
Merger merger = new Merger(rootFunction);
JsName internalModuleName = program.getScope().declareName("_");
Merger merger = new Merger(rootFunction, internalModuleName);
List<JsProgramFragment> fragments = new ArrayList<JsProgramFragment>();
for (KtFile file : files) {
@@ -279,8 +280,6 @@ public final class Translation {
List<JsStatement> statements = rootBlock.getStatements();
program.getScope().declareName("_");
//staticContext.postProcess();
statements.add(0, program.getStringLiteral("use strict").makeStmt());
if (!isBuiltinModule(fragments)) {
@@ -16,11 +16,11 @@
package org.jetbrains.kotlin.js.translate.intrinsic.objects
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.builtins.CompanionObjectMapping
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.StaticContext
import org.jetbrains.kotlin.js.translate.context.TranslationContext
@@ -29,10 +29,10 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
class DefaultClassObjectIntrinsic(val staticContext: StaticContext, val fqName: FqName): ObjectIntrinsic {
class DefaultClassObjectIntrinsic(val staticContext: StaticContext, val tag: String, val fqName: FqName): ObjectIntrinsic {
private val innerName: JsName by lazy {
val declaration = JsAstUtils.replaceRootReference(staticContext.getQualifiedReference(fqName), Namer.kotlinObject())
staticContext.importDeclaration(fqName.shortName().asString(), declaration)
staticContext.importDeclaration(fqName.shortName().asString(), tag, declaration)
}
override fun apply(context: TranslationContext) = JsAstUtils.pureFqn(innerName, null)
@@ -53,7 +53,8 @@ class ObjectIntrinsics(private val staticContext: StaticContext) {
val containingDeclaration = classDescriptor.containingDeclaration
val name = Name.identifier(containingDeclaration.name.asString() + "CompanionObject")
return DefaultClassObjectIntrinsic(staticContext, FqName("kotlin.js.internal").child(name))
return DefaultClassObjectIntrinsic(
staticContext, "intrinsic:kotlin.js.internal.${name.asString()}", FqName("kotlin.js.internal").child(name))
}
}
@@ -34,7 +34,7 @@ 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) {