diff --git a/build.xml b/build.xml index 08b67a4ee68..f23fb11a178 100644 --- a/build.xml +++ b/build.xml @@ -372,9 +372,6 @@ - - - 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 f90da8811f4..3f4df66a308 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/js/K2JSCompiler.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashMap; import kotlin.Unit; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; @@ -63,12 +64,21 @@ import org.jetbrains.kotlin.utils.PathUtil; import java.io.File; import java.util.List; +import java.util.Map; 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; public class K2JSCompiler extends CLICompiler { + private static final Map moduleKindMap = new HashMap(); + + static { + moduleKindMap.put(K2JSCompilerArguments.MODULE_PLAIN, ModuleKind.PLAIN); + moduleKindMap.put(K2JSCompilerArguments.MODULE_COMMONJS, ModuleKind.COMMON_JS); + moduleKindMap.put(K2JSCompilerArguments.MODULE_AMD, ModuleKind.AMD); + moduleKindMap.put(K2JSCompilerArguments.MODULE_UMD, ModuleKind.UMD); + } public static void main(String... args) { doMain(new K2JSCompiler(), args); @@ -274,29 +284,14 @@ public class K2JSCompiler extends CLICompiler { } configuration.put(JSConfigurationKeys.LIBRARY_FILES, libraryFiles); - String moduleKindName = arguments.moduleKind; - ModuleKind moduleKind = ModuleKind.PLAIN; - if (moduleKindName != null) { - moduleKindName = moduleKindName.toLowerCase(); - if (moduleKindName.equals(K2JSCompilerArguments.MODULE_PLAIN)) { - moduleKind = ModuleKind.PLAIN; - } - else if (moduleKindName.equals(K2JSCompilerArguments.MODULE_AMD)) { - moduleKind = ModuleKind.AMD; - } - else if (moduleKindName.equals(K2JSCompilerArguments.MODULE_COMMONJS)) { - moduleKind = ModuleKind.COMMON_JS; - } - else if (moduleKindName.equals(K2JSCompilerArguments.MODULE_UMD)) { - moduleKind = ModuleKind.UMD; - } - else { - messageCollector.report(CompilerMessageSeverity.ERROR, "Unknown module kind: " + moduleKindName + ". " + - "valid values are: plain, amd, commonjs", - CompilerMessageLocation.NO_LOCATION); - } - } + String moduleKindName = arguments.moduleKind; + ModuleKind moduleKind = moduleKindName != null ? moduleKindMap.get(moduleKindName) : ModuleKind.PLAIN; + if (moduleKind == null) { + messageCollector.report(CompilerMessageSeverity.ERROR, "Unknown module kind: " + moduleKindName + ". " + + "valid values are: plain, amd, commonjs, umd", + CompilerMessageLocation.NO_LOCATION); + } configuration.put(JSConfigurationKeys.MODULE_KIND, moduleKind); } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt index 1fd95ce8598..cac0baa5bf3 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializationUtil.kt @@ -236,7 +236,7 @@ object KotlinJavascriptSerializationUtil { private fun JsModuleDescriptor.toBinaryMetadata() = contentMapToByteArray(toContentMap(data), kind, imported) } -private fun ByteArray.toContentMap(): JsModuleProto { +private fun ByteArray.readAsContentMap(name: String): JsModuleDescriptor> { val gzipInputStream = GZIPInputStream(ByteArrayInputStream(this)) val content = JsProtoBuf.Library.parseFrom(gzipInputStream) gzipInputStream.close() @@ -244,8 +244,9 @@ private fun ByteArray.toContentMap(): JsModuleProto { val contentMap: MutableMap = hashMapOf() content.entryList.forEach { entry -> contentMap[entry.path] = entry.content.toByteArray() } - return JsModuleProto( - contentMap = contentMap, + return JsModuleDescriptor( + name = name, + data = contentMap, kind = when (content.kind) { null, JsProtoBuf.Library.Kind.PLAIN -> ModuleKind.PLAIN JsProtoBuf.Library.Kind.AMD -> ModuleKind.AMD @@ -254,6 +255,4 @@ private fun ByteArray.toContentMap(): JsModuleProto { }, imported = content.importedModulesList ) -} - -private class JsModuleProto(val contentMap: Map, val kind: ModuleKind, val imported: List) \ No newline at end of file +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/ModuleWrapperTranslation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/ModuleWrapperTranslation.java new file mode 100644 index 00000000000..c1db6f6fd58 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/ModuleWrapperTranslation.java @@ -0,0 +1,194 @@ +/* + * 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.general; + +import com.google.dart.compiler.backend.js.ast.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.js.translate.context.Namer; +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; +import org.jetbrains.kotlin.serialization.js.ModuleKind; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class ModuleWrapperTranslation { + private ModuleWrapperTranslation() { + } + + @NotNull + public static List wrapIfNecessary( + @Nullable String moduleId, + @NotNull JsExpression function, + @NotNull List importedModules, + @NotNull JsProgram program, + @NotNull ModuleKind kind + ) { + switch (kind) { + case AMD: + return wrapAmd(moduleId, function, importedModules, program); + case COMMON_JS: + return wrapCommonJs(function, importedModules, program); + case UMD: + return wrapUmd(moduleId, function, importedModules, program); + case PLAIN: + default: + return wrapPlain(moduleId, function, importedModules, program); + } + } + + @NotNull + private static List wrapUmd( + @Nullable String moduleId, + @NotNull JsExpression function, + @NotNull List importedModules, + @NotNull JsProgram program + ) { + JsScope scope = program.getScope(); + JsName rootName = scope.declareName("root"); + JsName factoryName = scope.declareName("factory"); + JsName defineName = scope.declareName("define"); + JsName exportsName = scope.declareName("exports"); + + JsExpression amdTest = JsAstUtils.and(JsAstUtils.typeOfIs(defineName.makeRef(), program.getStringLiteral("function")), + new JsNameRef("amd", defineName.makeRef())); + JsExpression commonJsTest = JsAstUtils.typeOfIs(exportsName.makeRef(), program.getStringLiteral("object")); + + JsBlock amdBody = new JsBlock(wrapAmd(moduleId, factoryName.makeRef(), importedModules, program)); + JsBlock commonJsBody = new JsBlock(wrapCommonJs(factoryName.makeRef(), importedModules, program)); + JsInvocation plainInvocation = makePlainInvocation(factoryName.makeRef(), importedModules, program); + + JsExpression plainExpr; + if (moduleId != null) { + JsExpression lhs = Namer.requiresEscaping(moduleId) ? + new JsArrayAccess(rootName.makeRef(), program.getStringLiteral(moduleId)) : + new JsNameRef(scope.declareName(moduleId), rootName.makeRef()); + plainExpr = JsAstUtils.assignment(lhs, plainInvocation); + } + else { + plainExpr = plainInvocation; + } + + JsStatement selector = JsAstUtils.newJsIf(amdTest, amdBody, JsAstUtils.newJsIf(commonJsTest, commonJsBody, plainExpr.makeStmt())); + JsFunction adapter = new JsFunction(program.getScope(), new JsBlock(selector), "UMD adapter"); + adapter.getParameters().add(new JsParameter(rootName)); + adapter.getParameters().add(new JsParameter(factoryName)); + + return Collections.singletonList(new JsInvocation(adapter, JsLiteral.THIS, function).makeStmt()); + } + + @NotNull + private static List wrapAmd( + @Nullable String moduleId, + @NotNull JsExpression function, + @NotNull List importedModules, + @NotNull JsProgram program + ) { + JsScope scope = program.getScope(); + JsName defineName = scope.declareName("define"); + List invocationArgs = new ArrayList(); + + if (moduleId != null) { + invocationArgs.add(program.getStringLiteral(moduleId)); + } + + List moduleNameList = new ArrayList(importedModules.size()); + for (ImportedModule importedModule : importedModules) { + moduleNameList.add(program.getStringLiteral(importedModule.id)); + } + invocationArgs.add(new JsArrayLiteral(moduleNameList)); + + invocationArgs.add(function); + + JsInvocation invocation = new JsInvocation(defineName.makeRef(), invocationArgs); + return Collections.singletonList(invocation.makeStmt()); + } + + @NotNull + private static List wrapCommonJs( + @NotNull JsExpression function, + @NotNull List importedModules, + @NotNull JsProgram program + ) { + JsScope scope = program.getScope(); + JsName moduleName = scope.declareName("module"); + JsName requireName = scope.declareName("require"); + + List invocationArgs = new ArrayList(); + for (ImportedModule importedModule : importedModules) { + invocationArgs.add(new JsInvocation(requireName.makeRef(), program.getStringLiteral(importedModule.id))); + } + + JsInvocation invocation = new JsInvocation(function, invocationArgs); + JsExpression assignment = JsAstUtils.assignment(new JsNameRef("exports", moduleName.makeRef()), invocation); + return Collections.singletonList(assignment.makeStmt()); + } + + @NotNull + private static List wrapPlain( + @Nullable String moduleId, + @NotNull JsExpression function, + @NotNull List importedModules, + @NotNull JsProgram program + ) { + JsInvocation invocation = makePlainInvocation(function, importedModules, program); + + JsStatement statement; + if (moduleId == null) { + statement = invocation.makeStmt(); + } + else { + statement = Namer.requiresEscaping(moduleId) ? + JsAstUtils.assignment(makePlainModuleRef(moduleId, program), invocation).makeStmt() : + JsAstUtils.newVar(program.getRootScope().declareName(moduleId), invocation); + } + + return Collections.singletonList(statement); + } + + @NotNull + private static JsInvocation makePlainInvocation(@NotNull JsExpression function, @NotNull List importedModules, + @NotNull JsProgram program) { + List invocationArgs = new ArrayList(importedModules.size()); + + for (ImportedModule importedModule : importedModules) { + invocationArgs.add(makePlainModuleRef(importedModule.id, program)); + } + + return new JsInvocation(function, invocationArgs); + } + + @NotNull + private static JsExpression makePlainModuleRef(@NotNull String moduleId, @NotNull JsProgram program) { + // TODO: we could use `this.moduleName` syntax. However, this does not work for `kotlin` module in Rhino, since + // we run kotlin.js in a parent scope. Consider better solution + return Namer.requiresEscaping(moduleId) ? + new JsArrayAccess(JsLiteral.THIS, program.getStringLiteral(moduleId)) : + program.getScope().declareName(moduleId).makeRef(); + } + + static final class ImportedModule { + @NotNull public final String id; + @NotNull public final JsName name; + + public ImportedModule(@NotNull String id, @NotNull JsName name) { + this.id = id; + this.name = name; + } + } +} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java index b38a4c74099..023d852665d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.js.translate.declaration.PackageDeclarationTranslato import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor; import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator; import org.jetbrains.kotlin.js.translate.expression.PatternTranslator; +import org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.ImportedModule; import org.jetbrains.kotlin.js.translate.test.JSRhinoUnitTester; import org.jetbrains.kotlin.js.translate.test.JSTestGenerator; import org.jetbrains.kotlin.js.translate.test.JSTester; @@ -57,6 +58,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.wrapIfNecessary; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement; import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.toStringLiteralList; @@ -188,16 +190,6 @@ public final class Translation { } } - private static class ImportedModule { - final String id; - final JsName name; - - public ImportedModule(String id, JsName name) { - this.id = id; - this.name = name; - } - } - @NotNull private static TranslationContext doGenerateAst( @NotNull BindingTrace bindingTrace, @@ -249,157 +241,6 @@ public final class Translation { return context; } - @NotNull - private static List wrapIfNecessary( - @NotNull String moduleId, - @NotNull JsExpression function, - @NotNull List importedModules, - @NotNull JsProgram program, - @NotNull ModuleKind kind - ) { - switch (kind) { - case AMD: - return wrapAmd(moduleId, function, importedModules, program); - case COMMON_JS: - return wrapCommonJs(function, importedModules, program); - case UMD: - return wrapUmd(moduleId, function, importedModules, program); - case PLAIN: - default: - return wrapPlain(moduleId, function, importedModules, program); - } - } - - @NotNull - private static List wrapUmd( - @Nullable String moduleId, - @NotNull JsExpression function, - @NotNull List importedModules, - @NotNull JsProgram program - ) { - JsScope scope = program.getScope(); - JsName rootName = scope.declareName("root"); - JsName factoryName = scope.declareName("factory"); - JsName defineName = scope.declareName("define"); - JsName exportsName = scope.declareName("exports"); - - JsExpression amdTest = JsAstUtils.and(JsAstUtils.typeOfIs(defineName.makeRef(), program.getStringLiteral("function")), - new JsNameRef("amd", defineName.makeRef())); - JsExpression commonJsTest = JsAstUtils.typeOfIs(exportsName.makeRef(), program.getStringLiteral("object")); - - JsBlock amdBody = new JsBlock(wrapAmd(moduleId, factoryName.makeRef(), importedModules, program)); - JsBlock commonJsBody = new JsBlock(wrapCommonJs(factoryName.makeRef(), importedModules, program)); - JsInvocation plainInvocation = makePlainInvocation(factoryName.makeRef(), importedModules, program); - - JsExpression plainExpr; - if (moduleId != null) { - JsExpression lhs = Namer.requiresEscaping(moduleId) ? - new JsArrayAccess(rootName.makeRef(), program.getStringLiteral(moduleId)) : - new JsNameRef(scope.declareName(moduleId), rootName.makeRef()); - plainExpr = JsAstUtils.assignment(lhs, plainInvocation); - } - else { - plainExpr = plainInvocation; - } - - JsStatement selector = JsAstUtils.newJsIf(amdTest, amdBody, JsAstUtils.newJsIf(commonJsTest, commonJsBody, plainExpr.makeStmt())); - JsFunction adapter = new JsFunction(program.getScope(), new JsBlock(selector), "UMD adapter"); - adapter.getParameters().add(new JsParameter(rootName)); - adapter.getParameters().add(new JsParameter(factoryName)); - - return Collections.singletonList(new JsInvocation(adapter, JsLiteral.THIS, function).makeStmt()); - } - - @NotNull - private static List wrapAmd( - @Nullable String moduleId, - @NotNull JsExpression function, - @NotNull List importedModules, - @NotNull JsProgram program - ) { - JsScope scope = program.getScope(); - JsName defineName = scope.declareName("define"); - List invocationArgs = new ArrayList(); - - if (moduleId != null) { - invocationArgs.add(program.getStringLiteral(moduleId)); - } - - List moduleNameList = new ArrayList(importedModules.size()); - for (ImportedModule importedModule : importedModules) { - moduleNameList.add(program.getStringLiteral(importedModule.id)); - } - invocationArgs.add(new JsArrayLiteral(moduleNameList)); - - invocationArgs.add(function); - - JsInvocation invocation = new JsInvocation(defineName.makeRef(), invocationArgs); - return Collections.singletonList(invocation.makeStmt()); - } - - @NotNull - private static List wrapCommonJs( - @NotNull JsExpression function, - @NotNull List importedModules, - @NotNull JsProgram program - ) { - JsScope scope = program.getScope(); - JsName moduleName = scope.declareName("module"); - JsName requireName = scope.declareName("require"); - - List invocationArgs = new ArrayList(); - for (ImportedModule importedModule : importedModules) { - invocationArgs.add(new JsInvocation(requireName.makeRef(), program.getStringLiteral(importedModule.id))); - } - - JsInvocation invocation = new JsInvocation(function, invocationArgs); - JsExpression assignment = JsAstUtils.assignment(new JsNameRef("exports", moduleName.makeRef()), invocation); - return Collections.singletonList(assignment.makeStmt()); - } - - @NotNull - private static List wrapPlain( - @Nullable String moduleId, - @NotNull JsExpression function, - @NotNull List importedModules, - @NotNull JsProgram program - ) { - JsInvocation invocation = makePlainInvocation(function, importedModules, program); - - JsStatement statement; - if (moduleId == null) { - statement = invocation.makeStmt(); - } - else { - statement = Namer.requiresEscaping(moduleId) ? - JsAstUtils.assignment(makePlainModuleRef(moduleId, program), invocation).makeStmt() : - JsAstUtils.newVar(program.getRootScope().declareName(moduleId), invocation); - } - - return Collections.singletonList(statement); - } - - @NotNull - private static JsInvocation makePlainInvocation(@NotNull JsExpression function, @NotNull List importedModules, - JsProgram program) { - List invocationArgs = new ArrayList(importedModules.size()); - - for (ImportedModule importedModule : importedModules) { - invocationArgs.add(makePlainModuleRef(importedModule.id, program)); - } - - return new JsInvocation(function, invocationArgs); - } - - @NotNull - private static JsExpression makePlainModuleRef(@NotNull String moduleId, @NotNull JsProgram program) { - // TODO: we could use `this.moduleName` syntax. However, this does not work for `kotlin` module in Rhino, since - // we run kotlin.js in a parent scope. Consider better solution - return Namer.requiresEscaping(moduleId) ? - new JsArrayAccess(JsLiteral.THIS, program.getStringLiteral(moduleId)) : - program.getScope().declareName(moduleId).makeRef(); - } - private static void defineModule(@NotNull TranslationContext context, @NotNull List statements, @NotNull String moduleId) { JsName rootPackageName = context.scope().findName(Namer.getRootPackageName()); if (rootPackageName != null) { diff --git a/js/js.translator/testData/merge.js b/js/js.translator/testData/merge.js index 76c6b2703bb..12902ffc742 100644 --- a/js/js.translator/testData/merge.js +++ b/js/js.translator/testData/merge.js @@ -1,4 +1,6 @@ +var stdlib = module.exports; var mergedRoot = Kotlin; + for (var propertyName in stdlib) { Kotlin[propertyName] = stdlib[propertyName]; } diff --git a/js/js.translator/testData/save-builtins.js b/js/js.translator/testData/save-builtins.js deleted file mode 100644 index bfbaae9dfd2..00000000000 --- a/js/js.translator/testData/save-builtins.js +++ /dev/null @@ -1,2 +0,0 @@ -var builtins = module.exports; -delete Kotlin.modules.kotlin; \ No newline at end of file diff --git a/js/js.translator/testData/save-stdlib.js b/js/js.translator/testData/save-stdlib.js deleted file mode 100644 index f043c4178df..00000000000 --- a/js/js.translator/testData/save-stdlib.js +++ /dev/null @@ -1,2 +0,0 @@ -var stdlib = module.exports; -delete Kotlin.modules.kotlin; \ No newline at end of file