JS: change how declarations are exported from modules. Change how parts of kotlin.js merged

This commit is contained in:
Alexey Andreev
2016-10-25 12:50:16 +03:00
parent 3d9beb15da
commit f244bbaae3
10 changed files with 1295 additions and 1336 deletions
+9 -11
View File
@@ -368,20 +368,9 @@
<sources dir="${js.stdlib.output.dir}"> <sources dir="${js.stdlib.output.dir}">
<file name="builtins.js"/> <file name="builtins.js"/>
</sources>
<sources dir="${stdlib.js.dir}">
<file name="merge-builtins.js"/>
</sources>
<sources dir="${js.stdlib.output.dir}">
<file name="${compiled.stdlib.js}"/> <file name="${compiled.stdlib.js}"/>
</sources> </sources>
<sources dir="${stdlib.js.dir}">
<file name="merge.js"/>
</sources>
<externs dir="${stdlib.js.dir}"> <externs dir="${stdlib.js.dir}">
<file name="externs.js"/> <file name="externs.js"/>
</externs> </externs>
@@ -412,6 +401,15 @@
<move file="${js.stdlib.output.dir}/tmp/kotlin" todir="${js.stdlib.output.dir}" /> <move file="${js.stdlib.output.dir}/tmp/kotlin" todir="${js.stdlib.output.dir}" />
<move file="${js.stdlib.output.dir}/tmp/${compiled.stdlib.meta.js}" tofile="${js.stdlib.output.dir}/${compiled.stdlib.meta.js}" /> <move file="${js.stdlib.output.dir}/tmp/${compiled.stdlib.meta.js}" tofile="${js.stdlib.output.dir}/${compiled.stdlib.meta.js}" />
<replaceregexp file="${js.stdlib.output.dir}/builtins.js"
match="module.exports,\s*require\([^)]+\)"
replace="Kotlin, Kotlin"
byline="true" encoding="UTF-8" />
<replaceregexp file="${js.stdlib.output.dir}/${compiled.stdlib.js}"
match="module.exports,\s*require\([^)]+\)"
replace="Kotlin, Kotlin"
byline="true" encoding="UTF-8" />
<condition property="jdk17" value="${env.JDK_17}" else="${env.JAVA_HOME}"> <condition property="jdk17" value="${env.JDK_17}" else="${env.JAVA_HOME}">
<isset property="env.JDK_17" /> <isset property="env.JDK_17" />
</condition> </condition>
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils;
@@ -145,15 +144,12 @@ public final class StaticContext {
@NotNull @NotNull
private final Set<ClassDescriptor> classes = new HashSet<ClassDescriptor>(); private final Set<ClassDescriptor> classes = new HashSet<ClassDescriptor>();
@NotNull
private final ExportedPackage rootPackage = new ExportedPackage("");
@NotNull
private final JsObjectLiteral exportObject = rootPackage.objectLiteral;
@NotNull @NotNull
private final Set<MemberDescriptor> exportedDeclarations = new HashSet<MemberDescriptor>(); private final Set<MemberDescriptor> exportedDeclarations = new HashSet<MemberDescriptor>();
@NotNull
private final Map<FqName, JsName> localPackageNames = new HashMap<FqName, JsName>();
//TODO: too many parameters in constructor //TODO: too many parameters in constructor
private StaticContext( private StaticContext(
@NotNull JsProgram program, @NotNull JsProgram program,
@@ -665,11 +661,7 @@ public final class StaticContext {
exportedDeclarations.add(descriptor); exportedDeclarations.add(descriptor);
if (container instanceof PackageFragmentDescriptor) { if (container instanceof PackageFragmentDescriptor) {
PackageFragmentDescriptor packageDescriptor = (PackageFragmentDescriptor) container; JsExpression packageRef = getLocalPackageReference(((PackageFragmentDescriptor) container).getFqName());
ExportedPackage exportedPackage = rootPackage;
for (Name packageName : packageDescriptor.getFqName().pathSegments()) {
exportedPackage = exportedPackage.getSubpackage(packageName.asString());
}
JsExpression initializerExpr = DeclarationExporter.exportDeclaration(this, descriptor, exportStatements); JsExpression initializerExpr = DeclarationExporter.exportDeclaration(this, descriptor, exportStatements);
if (initializerExpr != null) { if (initializerExpr != null) {
@@ -679,8 +671,7 @@ public final class StaticContext {
MetadataProperties.setStaticRef(propertyName, initializerExpr); MetadataProperties.setStaticRef(propertyName, initializerExpr);
} }
} }
JsPropertyInitializer initializer = new JsPropertyInitializer(propertyName.makeRef(), initializerExpr); exportStatements.add(JsAstUtils.assignment(new JsNameRef(propertyName, packageRef), initializerExpr).makeStmt());
exportedPackage.objectLiteral.getPropertyInitializers().add(initializer);
} }
} }
else { else {
@@ -689,6 +680,24 @@ public final class StaticContext {
} }
} }
private JsExpression getLocalPackageReference(FqName packageName) {
if (packageName.isRoot()) {
return rootFunction.getScope().declareName(Namer.getRootPackageName()).makeRef();
}
JsName name = localPackageNames.get(packageName);
if (name == null) {
name = rootFunction.getScope().declareFreshName("package$" + packageName.shortName().asString());
localPackageNames.put(packageName, name);
JsExpression parentRef = getLocalPackageReference(packageName.parent());
JsExpression selfRef = new JsNameRef(packageName.shortName().asString(), parentRef);
JsExpression rhs = JsAstUtils.or(selfRef, JsAstUtils.assignment(selfRef.deepCopy(), new JsObjectLiteral(false)));
exportStatements.add(JsAstUtils.newVar(name, rhs));
}
return name.makeRef();
}
@NotNull @NotNull
public NameSuggestion getNameSuggestion() { public NameSuggestion getNameSuggestion() {
return nameSuggestion; return nameSuggestion;
@@ -704,11 +713,7 @@ public final class StaticContext {
rootFunction.getBody().getStatements().addAll(importStatements); rootFunction.getBody().getStatements().addAll(importStatements);
addClassPrototypes(); addClassPrototypes();
rootFunction.getBody().getStatements().addAll(declarationStatements); rootFunction.getBody().getStatements().addAll(declarationStatements);
JsName rootPackageName = rootFunction.getScope().declareName(Namer.getRootPackageName());
rootFunction.getBody().getStatements().add(JsAstUtils.newVar(rootPackageName, exportObject));
rootFunction.getBody().getStatements().addAll(exportStatements); rootFunction.getBody().getStatements().addAll(exportStatements);
rootFunction.getBody().getStatements().addAll(topLevelStatements); rootFunction.getBody().getStatements().addAll(topLevelStatements);
} }
@@ -753,25 +758,4 @@ public final class StaticContext {
} }
return false; return false;
} }
private static class ExportedPackage {
@NotNull final String name;
@NotNull final Map<String, ExportedPackage> subpackages = new HashMap<String, ExportedPackage>();
@NotNull final JsObjectLiteral objectLiteral = new JsObjectLiteral(true);
public ExportedPackage(@NotNull String name) {
this.name = name;
}
@NotNull
public ExportedPackage getSubpackage(@NotNull String name) {
ExportedPackage subpackage = subpackages.get(name);
if (subpackage == null) {
subpackage = new ExportedPackage(name);
subpackages.put(name, subpackage);
objectLiteral.getPropertyInitializers().add(new JsPropertyInitializer(new JsNameRef(name), subpackage.objectLiteral));
}
return subpackage;
}
}
} }
@@ -55,7 +55,7 @@ object ModuleWrapperTranslation {
val amdBody = JsBlock(wrapAmd(moduleId, factoryName.makeRef(), importedModules, program)) val amdBody = JsBlock(wrapAmd(moduleId, factoryName.makeRef(), importedModules, program))
val commonJsBody = JsBlock(wrapCommonJs(factoryName.makeRef(), importedModules, program)) val commonJsBody = JsBlock(wrapCommonJs(factoryName.makeRef(), importedModules, program))
val plainInvocation = makePlainInvocation(factoryName.makeRef(), importedModules, program) val plainInvocation = makePlainInvocation(moduleId, factoryName.makeRef(), importedModules, program)
val lhs: JsExpression = if (Namer.requiresEscaping(moduleId)) { val lhs: JsExpression = if (Namer.requiresEscaping(moduleId)) {
JsArrayAccess(rootName.makeRef(), program.getStringLiteral(moduleId)) JsArrayAccess(rootName.makeRef(), program.getStringLiteral(moduleId))
@@ -79,7 +79,7 @@ object ModuleWrapperTranslation {
val defineName = scope.declareName("define") val defineName = scope.declareName("define")
val invocationArgs = listOf( val invocationArgs = listOf(
program.getStringLiteral(moduleId), program.getStringLiteral(moduleId),
JsArrayLiteral(importedModules.map { program.getStringLiteral(it) }), JsArrayLiteral(listOf(program.getStringLiteral("exports")) + importedModules.map { program.getStringLiteral(it) }),
function function
) )
@@ -93,16 +93,15 @@ object ModuleWrapperTranslation {
val requireName = scope.declareName("require") val requireName = scope.declareName("require")
val invocationArgs = importedModules.map { JsInvocation(requireName.makeRef(), program.getStringLiteral(it)) } val invocationArgs = importedModules.map { JsInvocation(requireName.makeRef(), program.getStringLiteral(it)) }
val invocation = JsInvocation(function, invocationArgs) val invocation = JsInvocation(function, listOf(JsNameRef("exports", moduleName.makeRef())) + invocationArgs)
val assignment = JsAstUtils.assignment(JsNameRef("exports", moduleName.makeRef()), invocation) return listOf(invocation.makeStmt())
return listOf(assignment.makeStmt())
} }
private fun wrapPlain( private fun wrapPlain(
moduleId: String, function: JsExpression, moduleId: String, function: JsExpression,
importedModules: List<String>, program: JsProgram importedModules: List<String>, program: JsProgram
): List<JsStatement> { ): List<JsStatement> {
val invocation = makePlainInvocation(function, importedModules, program) val invocation = makePlainInvocation(moduleId, function, importedModules, program)
val statement = if (Namer.requiresEscaping(moduleId)) { val statement = if (Namer.requiresEscaping(moduleId)) {
JsAstUtils.assignment(makePlainModuleRef(moduleId, program), invocation).makeStmt() JsAstUtils.assignment(makePlainModuleRef(moduleId, program), invocation).makeStmt()
@@ -114,9 +113,18 @@ object ModuleWrapperTranslation {
return listOf(statement) return listOf(statement)
} }
private fun makePlainInvocation(function: JsExpression, importedModules: List<String>, program: JsProgram): JsInvocation { private fun makePlainInvocation(
moduleId: String,
function: JsExpression,
importedModules: List<String>,
program: JsProgram
): JsInvocation {
val invocationArgs = importedModules.map { makePlainModuleRef(it, program) } val invocationArgs = importedModules.map { makePlainModuleRef(it, program) }
return JsInvocation(function, invocationArgs) val moduleRef = makePlainModuleRef(moduleId, program)
val testModuleDefined = JsAstUtils.typeOfIs(moduleRef, program.getStringLiteral("undefined"))
val selfArg = JsConditional(testModuleDefined, JsObjectLiteral(false), moduleRef.deepCopy())
return JsInvocation(function, listOf(selfArg) + invocationArgs)
} }
private fun makePlainModuleRef(moduleId: String, program: JsProgram): JsExpression { private fun makePlainModuleRef(moduleId: String, program: JsProgram): JsExpression {
@@ -269,6 +269,9 @@ public final class Translation {
mayBeGenerateTests(files, config, rootBlock, context); mayBeGenerateTests(files, config, rootBlock, context);
JsName rootPackageName = program.getRootScope().declareName(Namer.getRootPackageName());
rootFunction.getParameters().add(new JsParameter((rootPackageName)));
// Invoke function passing modules as arguments // Invoke function passing modules as arguments
// This should help minifier tool to recognize references to these modules as local variables and make them shorter. // This should help minifier tool to recognize references to these modules as local variables and make them shorter.
List<String> importedModuleList = new ArrayList<String>(); List<String> importedModuleList = new ArrayList<String>();
@@ -288,7 +291,7 @@ public final class Translation {
} }
} }
statements.add(new JsReturn(program.getRootScope().declareName(Namer.getRootPackageName()).makeRef())); statements.add(new JsReturn(rootPackageName.makeRef()));
JsBlock block = program.getGlobalBlock(); JsBlock block = program.getGlobalBlock();
block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program, block.getStatements().addAll(wrapIfNecessary(config.getModuleId(), rootFunction, importedModuleList, program,
+2 -5
View File
@@ -8,11 +8,8 @@
} }
}(this, function () { }(this, function () {
var Kotlin = {}; var Kotlin = {};
function require() {
return Kotlin;
}
var module = {};
%output% %output%
Kotlin.modules.kotlin = Kotlin;
return Kotlin; return Kotlin;
})); }));
+1 -5
View File
@@ -14,9 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
(function (Kotlin) {
"use strict";
// Shims for String // Shims for String
if (typeof String.prototype.startsWith === "undefined") { if (typeof String.prototype.startsWith === "undefined") {
String.prototype.startsWith = function(searchString, position) { String.prototype.startsWith = function(searchString, position) {
@@ -304,7 +301,6 @@
return result; return result;
}; };
var BaseOutput = Kotlin.createClassNow(null, null, { var BaseOutput = Kotlin.createClassNow(null, null, {
println: function (a) { println: function (a) {
if (typeof a !== "undefined") this.print(a); if (typeof a !== "undefined") this.print(a);
@@ -315,6 +311,7 @@
} }
); );
Kotlin.NodeJsOutput = Kotlin.createClassNow(BaseOutput, Kotlin.NodeJsOutput = Kotlin.createClassNow(BaseOutput,
function(outputStream) { function(outputStream) {
this.outputStream = outputStream; this.outputStream = outputStream;
@@ -499,5 +496,4 @@
}; };
Kotlin.identityHashCode = getObjectHashCode; Kotlin.identityHashCode = getObjectHashCode;
})(Kotlin);
-4
View File
@@ -26,9 +26,6 @@
// distributed under the License is distributed on an "AS-IS" BASIS, // distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
(function (Kotlin) {
"use strict";
/** /**
* Constructs a 64-bit two's-complement integer, given its low and high 32-bit * Constructs a 64-bit two's-complement integer, given its low and high 32-bit
* values as *signed* integers. See the from* functions below for more * values as *signed* integers. See the from* functions below for more
@@ -841,4 +838,3 @@
Kotlin.Long.prototype.rangeTo = function (other) { Kotlin.Long.prototype.rangeTo = function (other) {
return new Kotlin.kotlin.ranges.LongRange(this, other); return new Kotlin.kotlin.ranges.LongRange(this, other);
}; };
}(Kotlin));
-12
View File
@@ -1,12 +0,0 @@
var require = (function () {
var builtins = module.exports.kotlin;
var propertyNames = Object.getOwnPropertyNames(builtins);
Kotlin.kotlin = Kotlin.kotlin || {};
for (var i = 0; i < propertyNames.length; ++i) {
var propertyName = propertyNames[i];
Kotlin.kotlin[propertyName] = builtins[propertyName];
}
return function() {
return Kotlin;
}
})();
-16
View File
@@ -1,16 +0,0 @@
(function () {
var stdlib = module.exports;
function copyProperties(from, to) {
var propertyNames = Object.getOwnPropertyNames(from);
for (var i = 0; i < propertyNames.length; ++i) {
var propertyName = propertyNames[i];
if (propertyName in to) {
copyProperties(from[propertyName], to[propertyName]);
}
else {
to[propertyName] = from[propertyName];
}
}
}
copyProperties(stdlib, Kotlin);
})();
+7 -2
View File
@@ -16,9 +16,14 @@
function define(moduleId, dependencies, body) { function define(moduleId, dependencies, body) {
var resolvedDependencies = []; var resolvedDependencies = [];
emulatedModules[moduleId] = {};
for (var i = 0; i < dependencies.length; ++i) { for (var i = 0; i < dependencies.length; ++i) {
resolvedDependencies.push(emulatedModules[dependencies[i]]); var dependencyName = dependencies[i];
resolvedDependencies.push(emulatedModules[dependencyName === 'exports' ? moduleId : dependencyName]);
}
var result = body.apply(null, resolvedDependencies);
if (result != null) {
emulatedModules[moduleId] = result;
} }
emulatedModules[moduleId] = body.apply(null, resolvedDependencies);
} }
define.amd = {}; define.amd = {};