JS: use temporary names while translation, replace with fixed name during post-processing pass
This commit is contained in:
@@ -11,4 +11,6 @@ import com.google.dart.compiler.common.HasSymbol;
|
||||
*/
|
||||
public interface HasName extends HasSymbol {
|
||||
JsName getName();
|
||||
|
||||
void setName(JsName name);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ public class JsCatchScope extends JsScope {
|
||||
private final JsName name;
|
||||
|
||||
public JsCatchScope(JsScope parent, @NotNull String ident) {
|
||||
super(parent, "Catch scope", null);
|
||||
name = new JsName(this, ident);
|
||||
super(parent, "Catch scope");
|
||||
name = new JsName(this, ident, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -66,6 +66,7 @@ public final class JsFunction extends JsLiteral implements HasName {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(@Nullable JsName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Represents a JavaScript label statement.
|
||||
*/
|
||||
public class JsLabel extends SourceInfoAwareJsNode implements JsStatement, HasName {
|
||||
private final JsName label;
|
||||
private JsName label;
|
||||
|
||||
private JsStatement statement;
|
||||
|
||||
@@ -30,6 +30,11 @@ public class JsLabel extends SourceInfoAwareJsNode implements JsStatement, HasNa
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(JsName name) {
|
||||
label = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
return label;
|
||||
|
||||
@@ -12,17 +12,35 @@ import org.jetbrains.annotations.NotNull;
|
||||
* An abstract base class for named JavaScript objects.
|
||||
*/
|
||||
public class JsName extends HasMetadata implements Symbol {
|
||||
private static int ordinalGenerator;
|
||||
private final JsScope enclosing;
|
||||
private final int ordinal;
|
||||
|
||||
@NotNull
|
||||
private final String ident;
|
||||
|
||||
private final boolean temporary;
|
||||
|
||||
/**
|
||||
* @param ident the unmangled ident to use for this name
|
||||
*/
|
||||
JsName(JsScope enclosing, @NotNull String ident) {
|
||||
JsName(JsScope enclosing, @NotNull String ident, boolean temporary) {
|
||||
this.enclosing = enclosing;
|
||||
this.ident = ident;
|
||||
this.temporary = temporary;
|
||||
ordinal = temporary ? ordinalGenerator++ : 0;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
public JsScope getEnclosing() {
|
||||
return enclosing;
|
||||
}
|
||||
|
||||
public boolean isTemporary() {
|
||||
return temporary;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -39,21 +57,4 @@ public class JsName extends HasMetadata implements Symbol {
|
||||
public String toString() {
|
||||
return ident;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ident.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof JsName)) {
|
||||
return false;
|
||||
}
|
||||
JsName other = (JsName) obj;
|
||||
return ident.equals(other.ident) && enclosing == other.enclosing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,11 @@ public final class JsNameRef extends JsExpression implements HasName {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(JsName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public final class JsParameter extends SourceInfoAwareJsNode implements HasName {
|
||||
@NotNull
|
||||
private final JsName name;
|
||||
private JsName name;
|
||||
|
||||
public JsParameter(@NotNull JsName name) {
|
||||
this.name = name;
|
||||
@@ -24,6 +24,11 @@ public final class JsParameter extends SourceInfoAwareJsNode implements HasName
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(@NotNull JsName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Symbol getSymbol() {
|
||||
|
||||
@@ -28,9 +28,9 @@ public final class JsProgram extends SourceInfoAwareJsNode {
|
||||
private final Map<String, JsStringLiteral> stringLiteralMap = new THashMap<String, JsStringLiteral>();
|
||||
private final JsObjectScope topScope;
|
||||
|
||||
public JsProgram(String unitId) {
|
||||
public JsProgram() {
|
||||
rootScope = new JsRootScope(this);
|
||||
topScope = new JsObjectScope(rootScope, "Global", unitId);
|
||||
topScope = new JsObjectScope(rootScope, "Global");
|
||||
setFragmentCount(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,10 @@ import com.google.dart.compiler.util.Maps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope;
|
||||
|
||||
/**
|
||||
* A scope is a factory for creating and allocating
|
||||
@@ -46,14 +43,13 @@ public abstract class JsScope {
|
||||
@NotNull
|
||||
private final String description;
|
||||
private Map<String, JsName> names = Collections.emptyMap();
|
||||
private Map<JsName, Object> temporaryNames;
|
||||
private Set<JsName> readonlyTemporaryNames = null;
|
||||
private final JsScope parent;
|
||||
private int tempIndex = 0;
|
||||
private final String scopeId;
|
||||
|
||||
private static final Pattern FRESH_NAME_SUFFIX = Pattern.compile("[\\$_]\\d+$");
|
||||
|
||||
public JsScope(JsScope parent, @NotNull String description, @Nullable String scopeId) {
|
||||
this.scopeId = scopeId;
|
||||
public JsScope(JsScope parent, @NotNull String description) {
|
||||
this.description = description;
|
||||
this.parent = parent;
|
||||
}
|
||||
@@ -61,12 +57,21 @@ public abstract class JsScope {
|
||||
protected JsScope(@NotNull String description) {
|
||||
this.description = description;
|
||||
parent = null;
|
||||
scopeId = null;
|
||||
}
|
||||
|
||||
public Set<JsName> getTemporaryNames() {
|
||||
if (temporaryNames == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
if (readonlyTemporaryNames == null) {
|
||||
readonlyTemporaryNames = Collections.unmodifiableSet(temporaryNames.keySet());
|
||||
}
|
||||
return readonlyTemporaryNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsScope innerObjectScope(@NotNull String scopeName) {
|
||||
return JsObjectScope(this, scopeName);
|
||||
return new JsObjectScope(this, scopeName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,9 +102,15 @@ public abstract class JsScope {
|
||||
return doCreateName(ident);
|
||||
}
|
||||
|
||||
private String getNextTempName() {
|
||||
// introduced by the compiler
|
||||
return "tmp$" + (scopeId != null ? scopeId + "$" : "") + tempIndex++;
|
||||
@NotNull
|
||||
public JsName declareTemporaryName(@NotNull String suggestedName) {
|
||||
assert !suggestedName.isEmpty();
|
||||
JsName name = new JsName(this, suggestedName, true);
|
||||
if (temporaryNames == null) {
|
||||
temporaryNames = new WeakHashMap<JsName, Object>();
|
||||
}
|
||||
temporaryNames.put(name, this);
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +121,7 @@ public abstract class JsScope {
|
||||
*/
|
||||
@NotNull
|
||||
public JsName declareTemporary() {
|
||||
return declareFreshName(getNextTempName());
|
||||
return declareTemporaryName("tmp$");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,7 +182,7 @@ public abstract class JsScope {
|
||||
|
||||
@NotNull
|
||||
protected JsName doCreateName(@NotNull String ident) {
|
||||
JsName name = new JsName(this, ident);
|
||||
JsName name = new JsName(this, ident, false);
|
||||
names = Maps.put(names, ident, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterab
|
||||
* A var declared using the JavaScript <code>var</code> statement.
|
||||
*/
|
||||
public static class JsVar extends SourceInfoAwareJsNode implements HasName {
|
||||
private final JsName name;
|
||||
private JsName name;
|
||||
private JsExpression initExpression;
|
||||
|
||||
public JsVar(JsName name) {
|
||||
@@ -70,6 +70,11 @@ public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterab
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(JsName name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getSymbol() {
|
||||
return name;
|
||||
|
||||
@@ -18,15 +18,13 @@ package com.google.dart.compiler.backend.js.ast
|
||||
|
||||
import java.util.Stack
|
||||
|
||||
fun JsObjectScope(parent: JsScope, description: String): JsObjectScope = JsObjectScope(parent, description, null)
|
||||
class JsObjectScope(parent: JsScope, description: String) : JsScope(parent, description)
|
||||
|
||||
class JsObjectScope(parent: JsScope, description: String, scopeId: String?) : JsScope(parent, description, scopeId)
|
||||
|
||||
object JsDynamicScope : JsScope(null, "Scope for dynamic declarations", null) {
|
||||
override fun doCreateName(name: String) = JsName(this, name)
|
||||
object JsDynamicScope : JsScope(null, "Scope for dynamic declarations") {
|
||||
override fun doCreateName(name: String) = JsName(this, name, false)
|
||||
}
|
||||
|
||||
open class JsFunctionScope(parent: JsScope, description: String) : JsScope(parent, description, null) {
|
||||
open class JsFunctionScope(parent: JsScope, description: String) : JsScope(parent, description) {
|
||||
|
||||
private val labelScopes = Stack<LabelScope>()
|
||||
private val topLabelScope: LabelScope?
|
||||
@@ -50,7 +48,7 @@ open class JsFunctionScope(parent: JsScope, description: String) : JsScope(paren
|
||||
open fun findLabel(label: String): JsName? =
|
||||
topLabelScope?.findName(label)
|
||||
|
||||
private inner class LabelScope(parent: LabelScope?, val ident: String) : JsScope(parent, "Label scope for $ident", null) {
|
||||
private inner class LabelScope(parent: LabelScope?, val ident: String) : JsScope(parent, "Label scope for $ident") {
|
||||
val labelName: JsName
|
||||
|
||||
init {
|
||||
@@ -60,7 +58,7 @@ open class JsFunctionScope(parent: JsScope, description: String) : JsScope(paren
|
||||
else -> ident
|
||||
}
|
||||
|
||||
labelName = JsName(this@JsFunctionScope, freshIdent)
|
||||
labelName = JsName(this@JsFunctionScope, freshIdent, false)
|
||||
}
|
||||
|
||||
override fun findOwnName(name: String): JsName? =
|
||||
|
||||
@@ -87,10 +87,10 @@ class JsCallChecker(
|
||||
val errorReporter = JsCodeErrorReporter(argument, code, context.trace)
|
||||
|
||||
try {
|
||||
val parserScope = JsFunctionScope(JsRootScope(JsProgram("<js checker>")), "<js fun>")
|
||||
val parserScope = JsFunctionScope(JsRootScope(JsProgram()), "<js fun>")
|
||||
val statements = parse(code, errorReporter, parserScope)
|
||||
|
||||
if (statements.size == 0) {
|
||||
if (statements.isEmpty()) {
|
||||
context.trace.report(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED.on(argument))
|
||||
}
|
||||
} catch (e: AbortParsingException) {
|
||||
|
||||
@@ -148,7 +148,7 @@ class FunctionReader(private val context: TranslationContext) {
|
||||
offset++
|
||||
}
|
||||
|
||||
val function = parseFunction(source, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram("<inline>")))
|
||||
val function = parseFunction(source, offset, ThrowExceptionOnErrorReporter, JsRootScope(JsProgram()))
|
||||
val moduleName = getExternalModuleName(descriptor)!!
|
||||
val moduleReference = context.getModuleExpressionFor(descriptor) ?: getRootPackage()
|
||||
|
||||
|
||||
@@ -35,12 +35,10 @@ class RedundantBindElimination(private val root: JsBlock) {
|
||||
}
|
||||
|
||||
private fun tryEliminate(invocation: JsInvocation) {
|
||||
val qualifier = invocation.qualifier
|
||||
if (qualifier !is JsInvocation) return
|
||||
val qualifier = invocation.qualifier as? JsInvocation ?: return
|
||||
|
||||
val outerQualifier = qualifier.qualifier
|
||||
if (outerQualifier !is JsNameRef) return
|
||||
val name = outerQualifier.name?.ident ?: outerQualifier.ident
|
||||
val outerQualifier = qualifier.qualifier as? JsNameRef ?: return
|
||||
val name = outerQualifier.ident
|
||||
if (name != "bind") return
|
||||
|
||||
val qualifierReplacement = outerQualifier.qualifier ?: return
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.continuationInterfaceRef
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.interceptResumeRef
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.suspendObjectRef
|
||||
import org.jetbrains.kotlin.js.inline.util.collectReferencedTemporaryNames
|
||||
|
||||
fun JsNode.resolveTemporaryNames() {
|
||||
val scopeTree = ScopeCollector().let {
|
||||
it.accept(this)
|
||||
it.scopeTree
|
||||
}
|
||||
|
||||
val renamings = scopeTree.resolveNames()
|
||||
accept(object : RecursiveJsVisitor() {
|
||||
override fun visitElement(node: JsNode) {
|
||||
super.visitElement(node)
|
||||
if (node is HasName) {
|
||||
val name = node.name
|
||||
if (name != null) {
|
||||
renamings[name]?.let { node.name = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
x.continuationInterfaceRef?.let { accept(it) }
|
||||
x.interceptResumeRef?.let { accept(it) }
|
||||
x.suspendObjectRef?.let { accept(it) }
|
||||
super.visitFunction(x)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun Map<JsScope, Set<JsScope>>.resolveNames(): Map<JsName, JsName> {
|
||||
val replacements = mutableMapOf<JsName, JsName>()
|
||||
fun traverse(scope: JsScope) {
|
||||
for (temporaryName in scope.temporaryNames.sortedBy { it.ordinal }) {
|
||||
replacements[temporaryName] = scope.declareFreshName(temporaryName.ident).apply { copyMetadataFrom(temporaryName) }
|
||||
}
|
||||
this[scope]!!.forEach(::traverse)
|
||||
}
|
||||
|
||||
val roots = keys.toMutableSet()
|
||||
values.forEach { roots -= it }
|
||||
|
||||
for (root in roots) {
|
||||
traverse(root)
|
||||
}
|
||||
|
||||
return replacements
|
||||
}
|
||||
|
||||
private class ScopeCollector() : RecursiveJsVisitor() {
|
||||
val scopeTree = mutableMapOf<JsScope, MutableSet<JsScope>>()
|
||||
|
||||
override fun visitCatch(x: JsCatch) {
|
||||
recordScope(x.scope)
|
||||
super.visitCatch(x)
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
recordScope(x.scope)
|
||||
super.visitFunction(x)
|
||||
}
|
||||
override fun visitElement(node: JsNode) {
|
||||
if (node is HasName) {
|
||||
node.name?.let { recordScope(it.enclosing) }
|
||||
}
|
||||
super.visitElement(node)
|
||||
}
|
||||
|
||||
private fun recordScope(scope: JsScope) {
|
||||
if (scope !in scopeTree) {
|
||||
scopeTree[scope] = mutableSetOf()
|
||||
val parent = scope.parent
|
||||
if (parent != null) {
|
||||
recordScope(parent)
|
||||
scopeTree[parent]!!.add(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,11 @@ class NamingContext(
|
||||
|
||||
fun getFreshName(candidate: String): JsName = scope.declareFreshName(candidate)
|
||||
|
||||
fun getFreshName(candidate: JsName): JsName = getFreshName(candidate.ident)
|
||||
|
||||
fun getTemporaryName(candidate: String): JsName = scope.declareTemporaryName(candidate)
|
||||
|
||||
fun getFreshName(candidate: JsName) = if (candidate.isTemporary) getTemporaryName(candidate.ident) else getFreshName(candidate.ident)
|
||||
|
||||
|
||||
fun newVar(name: JsName, value: JsExpression? = null) {
|
||||
val vars = JsAstUtils.newVar(name, value)
|
||||
|
||||
@@ -18,12 +18,9 @@ package org.jetbrains.kotlin.js.inline.util
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
|
||||
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.InstanceCollector
|
||||
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.name
|
||||
import java.util.*
|
||||
|
||||
fun collectFunctionReferencesInside(scope: JsNode): List<JsName> =
|
||||
collectReferencedNames(scope).filter { it.staticRef is JsFunction }
|
||||
@@ -87,7 +84,7 @@ fun collectUsedNames(scope: JsNode): Set<JsName> {
|
||||
}
|
||||
|
||||
fun collectDefinedNames(scope: JsNode): Set<JsName> {
|
||||
val names: MutableMap<String, JsName> = HashMap()
|
||||
val names = mutableSetOf<JsName>()
|
||||
|
||||
object : RecursiveJsVisitor() {
|
||||
override fun visit(x: JsVars.JsVar) {
|
||||
@@ -95,7 +92,7 @@ fun collectDefinedNames(scope: JsNode): Set<JsName> {
|
||||
if (initializer != null) {
|
||||
accept(initializer)
|
||||
}
|
||||
addNameIfNeeded(x.name)
|
||||
names += x.name
|
||||
}
|
||||
|
||||
override fun visitExpressionStatement(x: JsExpressionStatement) {
|
||||
@@ -103,7 +100,7 @@ fun collectDefinedNames(scope: JsNode): Set<JsName> {
|
||||
if (expression is JsFunction) {
|
||||
val name = expression.name
|
||||
if (name != null) {
|
||||
addNameIfNeeded(name)
|
||||
names += name
|
||||
}
|
||||
}
|
||||
super.visitExpressionStatement(x)
|
||||
@@ -112,16 +109,9 @@ fun collectDefinedNames(scope: JsNode): Set<JsName> {
|
||||
// Skip function expression, since it does not introduce name in scope of containing function.
|
||||
// The only exception is function statement, that is handled with the code above.
|
||||
override fun visitFunction(x: JsFunction) { }
|
||||
|
||||
private fun addNameIfNeeded(name: JsName) {
|
||||
val ident = name.ident
|
||||
val nameCollected = names[ident]
|
||||
assert(nameCollected == null || nameCollected === name) { "ambiguous identifier $name" }
|
||||
names[ident] = name
|
||||
}
|
||||
}.accept(scope)
|
||||
|
||||
return names.values.toSet()
|
||||
return names
|
||||
}
|
||||
|
||||
fun JsFunction.collectFreeVariables() = collectUsedNames(body) - collectDefinedNames(body) - parameters.map { it.name }
|
||||
|
||||
@@ -58,8 +58,8 @@ fun renameLocalNames(
|
||||
function: JsFunction
|
||||
) {
|
||||
for (name in collectDefinedNames(function.body)) {
|
||||
val freshName = context.getFreshName(name).apply { staticRef = name.staticRef }
|
||||
context.replaceName(name, freshName.makeRef())
|
||||
val temporaryName = context.getTemporaryName(name.ident).apply { staticRef = name.staticRef }
|
||||
context.replaceName(name, temporaryName.makeRef())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
||||
}
|
||||
|
||||
private fun checkOptimizer(unoptimizedCode: String, optimizedCode: String) {
|
||||
val parserScope = JsFunctionScope(JsRootScope(JsProgram("<js checker>")), "<js fun>")
|
||||
val parserScope = JsFunctionScope(JsRootScope(JsProgram()), "<js fun>")
|
||||
val unoptimizedAst = parse(unoptimizedCode, errorReporter, parserScope)
|
||||
|
||||
updateMetadata(unoptimizedCode, unoptimizedAst)
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
||||
import org.jetbrains.kotlin.js.inline.JsInliner;
|
||||
import org.jetbrains.kotlin.js.translate.context.StaticContext;
|
||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
||||
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation;
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
|
||||
@@ -85,6 +86,7 @@ public final class K2JSTranslator {
|
||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||
|
||||
JsProgram program = JsInliner.process(context);
|
||||
ResolveTemporaryNamesKt.resolveTemporaryNames(program);
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.js.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
@@ -32,10 +31,10 @@ public class AliasingContext {
|
||||
return new AliasingContext(null, null, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
private final Map<DeclarationDescriptor, JsExpression> aliasesForDescriptors;
|
||||
|
||||
@NotNull
|
||||
@Nullable
|
||||
private final Map<KtExpression, JsExpression> aliasesForExpressions;
|
||||
|
||||
@Nullable
|
||||
@@ -47,8 +46,8 @@ public class AliasingContext {
|
||||
@Nullable Map<KtExpression, JsExpression> aliasesForExpressions
|
||||
) {
|
||||
this.parent = parent;
|
||||
this.aliasesForDescriptors = aliasesForDescriptors == null ? Collections.<DeclarationDescriptor, JsExpression>emptyMap() : aliasesForDescriptors;
|
||||
this.aliasesForExpressions = aliasesForExpressions == null ? Collections.<KtExpression, JsExpression>emptyMap() : aliasesForExpressions;
|
||||
this.aliasesForDescriptors = aliasesForDescriptors;
|
||||
this.aliasesForExpressions = aliasesForExpressions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -74,13 +73,13 @@ public class AliasingContext {
|
||||
@Nullable
|
||||
public JsExpression getAliasForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
// these aliases cannot be shared and applicable only in current context
|
||||
JsExpression alias = aliasesForDescriptors.get(descriptor.getOriginal());
|
||||
JsExpression alias = aliasesForDescriptors != null ? aliasesForDescriptors.get(descriptor.getOriginal()) : null;
|
||||
return alias != null || parent == null ? alias : parent.getAliasForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getAliasForExpression(@NotNull KtExpression element) {
|
||||
JsExpression alias = aliasesForExpressions.get(element);
|
||||
JsExpression alias = aliasesForExpressions != null ? aliasesForExpressions.get(element) : null;
|
||||
return alias != null || parent == null ? alias : parent.getAliasForExpression(element);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -105,7 +105,7 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
val setterBody: JsExpression = if (simpleProperty) {
|
||||
val statements = mutableListOf<JsStatement>()
|
||||
val function = JsFunction(context.rootFunction.scope, JsBlock(statements), "$declaration setter")
|
||||
val valueName = function.scope.declareFreshName("value")
|
||||
val valueName = function.scope.declareTemporaryName("value")
|
||||
function.parameters += JsParameter(valueName)
|
||||
statements += assignment(context.getInnerNameForDescriptor(declaration).makeRef(), valueName.makeRef()).makeStmt()
|
||||
function
|
||||
@@ -125,7 +125,7 @@ internal class DeclarationExporter(val context: StaticContext) {
|
||||
}
|
||||
var name = localPackageNames[packageName]
|
||||
if (name == null) {
|
||||
name = context.rootFunction.scope.declareFreshName("package$" + packageName.shortName().asString())
|
||||
name = context.rootFunction.scope.declareTemporaryName("package$" + packageName.shortName().asString())
|
||||
localPackageNames.put(packageName, name)
|
||||
|
||||
val parentRef = getLocalPackageReference(packageName.parent())
|
||||
|
||||
@@ -43,7 +43,6 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.dart.compiler.backend.js.ast.JsScopesKt.JsObjectScope;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
|
||||
|
||||
@@ -127,7 +126,9 @@ public final class Namer {
|
||||
qualifier = fqNameParent.asString();
|
||||
}
|
||||
|
||||
String mangledName = new NameSuggestion().suggest(functionDescriptor).getNames().get(0);
|
||||
SuggestedName suggestedName = new NameSuggestion().suggest(functionDescriptor);
|
||||
assert suggestedName != null : "Suggested name can be null only for module descriptors: " + functionDescriptor;
|
||||
String mangledName = suggestedName.getNames().get(0);
|
||||
return StringUtil.join(Arrays.asList(moduleName, qualifier, mangledName), ".");
|
||||
}
|
||||
|
||||
@@ -226,7 +227,7 @@ public final class Namer {
|
||||
private final JsName isTypeName;
|
||||
|
||||
private Namer(@NotNull JsScope rootScope) {
|
||||
kotlinScope = JsObjectScope(rootScope, "Kotlin standard object");
|
||||
kotlinScope = new JsObjectScope(rootScope, "Kotlin standard object");
|
||||
|
||||
callGetProperty = kotlin("callGetter");
|
||||
callSetProperty = kotlin("callSetter");
|
||||
|
||||
@@ -64,7 +64,7 @@ public final class StaticContext {
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull JsConfig config,
|
||||
@NotNull ModuleDescriptor moduleDescriptor) {
|
||||
JsProgram program = new JsProgram("main");
|
||||
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);
|
||||
@@ -146,6 +146,9 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private final Set<ClassDescriptor> classes = new LinkedHashSet<ClassDescriptor>();
|
||||
|
||||
@NotNull
|
||||
private final Map<FqName, JsScope> packageScopes = new HashMap<FqName, JsScope>();
|
||||
|
||||
//TODO: too many parameters in constructor
|
||||
private StaticContext(
|
||||
@NotNull JsProgram program,
|
||||
@@ -165,7 +168,7 @@ public final class StaticContext {
|
||||
this.config = config;
|
||||
this.currentModule = moduleDescriptor;
|
||||
this.rootFunction = rootFunction;
|
||||
rootPackageScope = new JsObjectScope(rootScope, "<root package>", "root-package");
|
||||
rootPackageScope = new JsObjectScope(rootScope, "<root package>");
|
||||
|
||||
JsName kotlinName = rootScope.declareName(Namer.KOTLIN_NAME);
|
||||
importedModules.put(new ImportedModuleKey(Namer.KOTLIN_LOWER_NAME, null),
|
||||
@@ -362,10 +365,15 @@ public final class StaticContext {
|
||||
JsName name = nameCache.get(suggested.getDescriptor());
|
||||
if (name == null) {
|
||||
String baseName = suggested.getNames().get(0);
|
||||
if (!DescriptorUtils.isDescriptorWithLocalVisibility(suggested.getDescriptor())) {
|
||||
baseName += "_0";
|
||||
if (suggested.getDescriptor() instanceof LocalVariableDescriptor) {
|
||||
name = scope.declareTemporaryName(baseName);
|
||||
}
|
||||
else {
|
||||
if (!DescriptorUtils.isDescriptorWithLocalVisibility(suggested.getDescriptor())) {
|
||||
baseName += "_0";
|
||||
}
|
||||
name = scope.declareFreshName(baseName);
|
||||
}
|
||||
name = scope.declareFreshName(baseName);
|
||||
}
|
||||
nameCache.put(suggested.getDescriptor(), name);
|
||||
names.add(name);
|
||||
@@ -425,7 +433,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().declareFreshName("imported$" + suggestedName);
|
||||
JsName result = rootFunction.getScope().declareTemporaryName(suggestedName);
|
||||
MetadataProperties.setImported(result, true);
|
||||
importStatements.add(JsAstUtils.newVar(result, declaration));
|
||||
return result;
|
||||
@@ -436,7 +444,7 @@ public final class StaticContext {
|
||||
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
|
||||
return module != currentModule ?
|
||||
importDeclaration(suggestedName, getQualifiedReference(descriptor)) :
|
||||
rootFunction.getScope().declareFreshName(suggestedName);
|
||||
rootFunction.getScope().declareTemporaryName(suggestedName);
|
||||
}
|
||||
|
||||
private final class InnerNameGenerator extends Generator<JsName> {
|
||||
@@ -529,6 +537,21 @@ public final class StaticContext {
|
||||
return suggestedName;
|
||||
}
|
||||
|
||||
private JsScope getScopeForPackage(FqName fqName) {
|
||||
JsScope scope = packageScopes.get(fqName);
|
||||
if (scope == null) {
|
||||
if (fqName.isRoot()) {
|
||||
scope = new JsRootScope(program);
|
||||
}
|
||||
else {
|
||||
JsScope parentScope = getScopeForPackage(fqName.parent());
|
||||
scope = parentScope.innerObjectScope(fqName.shortName().asString());
|
||||
}
|
||||
packageScopes.put(fqName, scope);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
private final class ScopeGenerator extends Generator<JsScope> {
|
||||
|
||||
public ScopeGenerator() {
|
||||
@@ -539,7 +562,7 @@ public final class StaticContext {
|
||||
return null;
|
||||
}
|
||||
if (getSuperclass((ClassDescriptor) descriptor) == null) {
|
||||
JsFunction function = new JsFunction(rootFunction.getScope(), new JsBlock(), descriptor.toString());
|
||||
JsFunction function = new JsFunction(new JsRootScope(program), new JsBlock(), descriptor.toString());
|
||||
scopeToFunction.put(function.getScope(), function);
|
||||
return function.getScope();
|
||||
}
|
||||
@@ -585,6 +608,17 @@ public final class StaticContext {
|
||||
return correspondingFunction.getScope();
|
||||
}
|
||||
};
|
||||
Rule<JsScope> scopeForPackage = new Rule<JsScope>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JsScope apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof PackageFragmentDescriptor)) return null;
|
||||
|
||||
PackageFragmentDescriptor packageDescriptor = (PackageFragmentDescriptor) descriptor;
|
||||
return getScopeForPackage(packageDescriptor.getFqName());
|
||||
}
|
||||
};
|
||||
addRule(scopeForPackage);
|
||||
addRule(createFunctionObjectsForCallableDescriptors);
|
||||
addRule(generateNewScopesForClassesWithNoAncestors);
|
||||
addRule(generateInnerScopesForDerivedClasses);
|
||||
@@ -625,7 +659,7 @@ public final class StaticContext {
|
||||
|
||||
ImportedModule module = importedModules.get(key);
|
||||
if (module == null) {
|
||||
JsName internalName = rootScope.declareFreshName(Namer.LOCAL_MODULE_PREFIX + Namer.suggestedModuleName(baseName));
|
||||
JsName internalName = rootScope.declareTemporaryName(Namer.LOCAL_MODULE_PREFIX + Namer.suggestedModuleName(baseName));
|
||||
JsName plainName = descriptor != null ? rootScope.declareName(getPlainId(descriptor)) : null;
|
||||
module = new ImportedModule(baseName, internalName, plainName != null ? pureFqn(plainName, null) : null);
|
||||
importedModules.put(key, module);
|
||||
|
||||
+1
-1
@@ -607,7 +607,7 @@ public class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
public JsName createGlobalName(@NotNull String suggestedName) {
|
||||
return staticContext.getRootFunction().getScope().declareFreshName(suggestedName);
|
||||
return staticContext.getRootFunction().getScope().declareTemporaryName(suggestedName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -49,9 +49,6 @@ class UsageTracker(
|
||||
|
||||
// local named function
|
||||
if (descriptor is FunctionDescriptor && descriptor.visibility == Visibilities.LOCAL) {
|
||||
assert(descriptor.isCoroutineLambda || !descriptor.getName().isSpecial) {
|
||||
"Function with special name can not be captured, descriptor: $descriptor"
|
||||
}
|
||||
captureIfNeed(descriptor)
|
||||
}
|
||||
// local variable
|
||||
|
||||
+4
-4
@@ -150,8 +150,8 @@ class ClassTranslator private constructor(
|
||||
}
|
||||
|
||||
private fun addEnumClassParameters(constructorFunction: JsFunction) {
|
||||
val nameParamName = constructorFunction.scope.declareFreshName("name")
|
||||
val ordinalParamName = constructorFunction.scope.declareFreshName("ordinal")
|
||||
val nameParamName = constructorFunction.scope.declareTemporaryName("name")
|
||||
val ordinalParamName = constructorFunction.scope.declareTemporaryName("ordinal")
|
||||
constructorFunction.parameters.addAll(0, listOf(JsParameter(nameParamName), JsParameter(ordinalParamName)))
|
||||
|
||||
constructorFunction.body.statements += JsAstUtils.assignmentToThisField(Namer.ENUM_NAME_FIELD, nameParamName.makeRef())
|
||||
@@ -232,8 +232,8 @@ class ClassTranslator private constructor(
|
||||
val leadingArgs = mutableListOf<JsExpression>()
|
||||
|
||||
if (descriptor.kind == ClassKind.ENUM_CLASS) {
|
||||
val nameParamName = constructorInitializer.scope.declareFreshName("name")
|
||||
val ordinalParamName = constructorInitializer.scope.declareFreshName("ordinal")
|
||||
val nameParamName = constructorInitializer.scope.declareTemporaryName("name")
|
||||
val ordinalParamName = constructorInitializer.scope.declareTemporaryName("ordinal")
|
||||
constructorInitializer.parameters.addAll(0, listOf(JsParameter(nameParamName), JsParameter(ordinalParamName)))
|
||||
leadingArgs += listOf(nameParamName.makeRef(), ordinalParamName.makeRef())
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ class EnumTranslator(
|
||||
private fun generateValueOfFunction() {
|
||||
val function = createFunction(getEnumFunction(DescriptorUtils.ENUM_VALUE_OF))
|
||||
|
||||
val nameParam = function.scope.declareFreshName("name")
|
||||
val nameParam = function.scope.declareTemporaryName("name")
|
||||
function.parameters += JsParameter(nameParam)
|
||||
|
||||
val clauses = entries.map { entry ->
|
||||
|
||||
+9
-8
@@ -17,13 +17,13 @@
|
||||
package org.jetbrains.kotlin.js.translate.declaration;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
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 org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -42,13 +42,14 @@ public final class PackageDeclarationTranslator extends AbstractTranslator {
|
||||
|
||||
private void translate() {
|
||||
for (KtFile file : files) {
|
||||
PackageFragmentDescriptor packageFragment =
|
||||
BindingContextUtils.getNotNull(context().bindingContext(), BindingContext.FILE_TO_PACKAGE_FRAGMENT, file);
|
||||
|
||||
PackageTranslator translator = PackageTranslator.create(packageFragment, context());
|
||||
FileDeclarationVisitor fileVisitor = new FileDeclarationVisitor(context());
|
||||
|
||||
try {
|
||||
translator.translate(file);
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (!AnnotationsUtils.isPredefinedObject(BindingUtils.getDescriptorForElement(bindingContext(), declaration))) {
|
||||
declaration.accept(fileVisitor, context());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TranslationRuntimeException e) {
|
||||
throw e;
|
||||
|
||||
-55
@@ -1,55 +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.descriptors.PackageFragmentDescriptor;
|
||||
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;
|
||||
|
||||
final class PackageTranslator extends AbstractTranslator {
|
||||
static PackageTranslator create(
|
||||
@NotNull PackageFragmentDescriptor descriptor,
|
||||
@NotNull TranslationContext context
|
||||
) {
|
||||
TranslationContext newContext = context.newDeclaration(descriptor);
|
||||
FileDeclarationVisitor visitor = new FileDeclarationVisitor(newContext);
|
||||
return new PackageTranslator(newContext, visitor);
|
||||
}
|
||||
|
||||
private final FileDeclarationVisitor visitor;
|
||||
|
||||
private PackageTranslator(
|
||||
@NotNull TranslationContext context,
|
||||
@NotNull FileDeclarationVisitor visitor
|
||||
) {
|
||||
super(context);
|
||||
this.visitor = visitor;
|
||||
}
|
||||
|
||||
public void translate(KtFile file) {
|
||||
for (KtDeclaration declaration : file.getDeclarations()) {
|
||||
if (!AnnotationsUtils.isPredefinedObject(BindingUtils.getDescriptorForElement(bindingContext(), declaration))) {
|
||||
declaration.accept(visitor, context());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-7
@@ -460,13 +460,14 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
JsExpression alias = new LiteralFunctionTranslator(context).translate(expression, null, null);
|
||||
|
||||
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
|
||||
JsName name = context.getNameForDescriptor(descriptor);
|
||||
JsNameRef nameRef = (JsNameRef) ReferenceTranslator.translateAsValueReference(descriptor, context);
|
||||
assert nameRef.getName() != null;
|
||||
if (InlineUtil.isInline(descriptor)) {
|
||||
MetadataProperties.setStaticRef(name, alias);
|
||||
MetadataProperties.setStaticRef(nameRef.getName(), alias);
|
||||
}
|
||||
|
||||
boolean isExpression = BindingContextUtilsKt.isUsedAsExpression(expression, context.bindingContext());
|
||||
JsNode result = isExpression ? alias : JsAstUtils.newVar(name, alias);
|
||||
JsNode result = isExpression ? alias : JsAstUtils.newVar(nameRef.getName(), alias);
|
||||
|
||||
return result.source(expression);
|
||||
}
|
||||
@@ -552,10 +553,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
ResolvedCall<FunctionDescriptor> superCall = BindingUtils.getSuperCall(context.bindingContext(),
|
||||
expression.getObjectDeclaration());
|
||||
if (superCall != null) {
|
||||
assert context.getDeclarationDescriptor() != null : "This expression should be inside declaration: " +
|
||||
PsiUtilsKt.getTextWithLocation(expression);
|
||||
TranslationContext superCallContext = context.newDeclaration(context.getDeclarationDescriptor());
|
||||
closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, superCallContext).getTranslateArguments());
|
||||
closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, context).getTranslateArguments());
|
||||
}
|
||||
|
||||
return new JsNew(constructor, closureArgs);
|
||||
|
||||
+15
-4
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.context.AliasingContext;
|
||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
|
||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression;
|
||||
@@ -78,17 +79,27 @@ public final class FunctionTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private TranslationContext getFunctionBodyContext() {
|
||||
AliasingContext aliasingContext;
|
||||
Map<DeclarationDescriptor, JsExpression> aliases = new HashMap<DeclarationDescriptor, JsExpression>();
|
||||
if (isExtensionFunction()) {
|
||||
DeclarationDescriptor expectedReceiverDescriptor = descriptor.getExtensionReceiverParameter();
|
||||
assert expectedReceiverDescriptor != null;
|
||||
extensionFunctionReceiverName = functionObject.getScope().declareName(Namer.getReceiverParameterName());
|
||||
//noinspection ConstantConditions
|
||||
aliasingContext = context().aliasingContext().inner(expectedReceiverDescriptor, extensionFunctionReceiverName.makeRef());
|
||||
aliases.put(expectedReceiverDescriptor, extensionFunctionReceiverName.makeRef());
|
||||
}
|
||||
else {
|
||||
aliasingContext = null;
|
||||
|
||||
LocalFunctionCollector functionCollector = new LocalFunctionCollector(context().bindingContext());
|
||||
functionDeclaration.acceptChildren(functionCollector, null);
|
||||
for (FunctionDescriptor localFunction : functionCollector.getFunctions()) {
|
||||
String localIdent = localFunction.getName().isSpecial() ? "lambda" : localFunction.getName().asString();
|
||||
JsName localName = functionObject.getScope().getParent().declareTemporaryName(localIdent);
|
||||
JsExpression alias = JsAstUtils.pureFqn(localName, null);
|
||||
aliases.put(localFunction, alias);
|
||||
}
|
||||
|
||||
AliasingContext aliasingContext = !aliases.isEmpty() ? context().aliasingContext().withDescriptorsAliased(aliases) : null;
|
||||
|
||||
|
||||
return context().newFunctionBody(functionObject, aliasingContext, descriptor);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -264,7 +264,7 @@ private fun moveCapturedLocalInside(capturingFunction: JsFunction, capturedName:
|
||||
val capturedArgs = localFunAlias.arguments
|
||||
|
||||
val scope = capturingFunction.getInnerFunction()?.scope!!
|
||||
val freshNames = getFreshNamesInScope(scope, capturedArgs)
|
||||
val freshNames = getTemporaryNamesInScope(scope, capturedArgs)
|
||||
|
||||
val aliasCallArguments = freshNames.map { it.makeRef() }
|
||||
val alias = JsInvocation(localFunAlias.qualifier, aliasCallArguments)
|
||||
@@ -279,7 +279,7 @@ private fun declareAliasInsideFunction(function: JsFunction, name: JsName, alias
|
||||
function.getInnerFunction()?.addDeclaration(name, alias)
|
||||
}
|
||||
|
||||
private fun getFreshNamesInScope(scope: JsScope, suggested: List<JsExpression>): List<JsName> {
|
||||
private fun getTemporaryNamesInScope(scope: JsScope, suggested: List<JsExpression>): List<JsName> {
|
||||
val freshNames = arrayListOf<JsName>()
|
||||
|
||||
for (suggestion in suggested) {
|
||||
@@ -288,7 +288,7 @@ private fun getFreshNamesInScope(scope: JsScope, suggested: List<JsExpression>):
|
||||
}
|
||||
|
||||
val ident = suggestion.ident
|
||||
val name = scope.declareFreshName(ident)
|
||||
val name = scope.declareTemporaryName(ident)
|
||||
freshNames.add(name)
|
||||
}
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
|
||||
class LocalFunctionCollector(val bindingContext: BindingContext) : KtVisitorVoid() {
|
||||
val functions = mutableSetOf<FunctionDescriptor>()
|
||||
|
||||
override fun visitExpression(expression: KtExpression) {
|
||||
if (expression is KtDeclarationWithBody) {
|
||||
functions += BindingUtils.getFunctionDescriptor(bindingContext, expression)
|
||||
}
|
||||
else {
|
||||
expression.acceptChildren(this, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
// skip
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -122,7 +122,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
|
||||
// but no new global ones.
|
||||
JsScope currentScope = context().scope();
|
||||
assert currentScope instanceof JsFunctionScope : "Usage of js outside of function is unexpected";
|
||||
JsScope temporaryRootScope = new JsRootScope(new JsProgram("<js code>"));
|
||||
JsScope temporaryRootScope = new JsRootScope(new JsProgram());
|
||||
JsScope scope = new DelegatingJsFunctionScopeWithTemporaryParent((JsFunctionScope) currentScope, temporaryRootScope);
|
||||
return ParserUtilsKt.parse(jsCode, ThrowExceptionOnErrorReporter.INSTANCE, scope);
|
||||
}
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ object CallableReferenceTranslator {
|
||||
}
|
||||
|
||||
val function = context.createRootScopedFunction(setter)
|
||||
val valueParam = function.scope.declareFreshName("value")
|
||||
val valueParam = function.scope.declareTemporaryName("value")
|
||||
function.parameters += JsParameter(valueParam)
|
||||
|
||||
val expression = if (TranslationUtils.shouldAccessViaFunctions(descriptor)) {
|
||||
|
||||
@@ -24,7 +24,7 @@ fun JsFunction.addStatement(stmt: JsStatement) {
|
||||
}
|
||||
|
||||
fun JsFunction.addParameter(identifier: String, index: Int? = null): JsParameter {
|
||||
val name = scope.declareFreshName(identifier)
|
||||
val name = scope.declareTemporaryName(identifier)
|
||||
val parameter = JsParameter(name)
|
||||
|
||||
if (index == null) {
|
||||
|
||||
@@ -41,14 +41,14 @@ fun generateDelegateCall(
|
||||
val functionScope = context.getScopeForDescriptor(fromDescriptor)
|
||||
|
||||
if (DescriptorUtils.isExtension(fromDescriptor)) {
|
||||
val extensionFunctionReceiverName = functionScope.declareFreshName(Namer.getReceiverParameterName())
|
||||
val extensionFunctionReceiverName = functionScope.declareTemporaryName(Namer.getReceiverParameterName())
|
||||
parameters.add(JsParameter(extensionFunctionReceiverName))
|
||||
args.add(JsNameRef(extensionFunctionReceiverName))
|
||||
}
|
||||
|
||||
for (param in fromDescriptor.valueParameters) {
|
||||
val paramName = param.name.asString()
|
||||
val jsParamName = functionScope.declareFreshName(paramName)
|
||||
val jsParamName = functionScope.declareTemporaryName(paramName)
|
||||
parameters.add(JsParameter(jsParamName))
|
||||
args.add(JsNameRef(jsParamName))
|
||||
}
|
||||
|
||||
+8
-8
@@ -6,29 +6,29 @@ fun fail(message: String? = null): Nothing = js("throw new Error(message)")
|
||||
|
||||
fun <T> assertEquals(expected: T, actual: T, message: String? = null) {
|
||||
if (expected != actual) {
|
||||
val msg = if (message == null) "" else (" message = '" + message + "',")
|
||||
fail("Unexpected value:$msg expected = '$expected', actual = '$actual'")
|
||||
val msg = if (message == null) "" else ", message = '$message'"
|
||||
fail("Unexpected value: expected = '$expected', actual = '$actual'$msg")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> assertNotEquals(illegal: T, actual: T, message: String? = null) {
|
||||
if (illegal == actual) {
|
||||
val msg = if (message == null) "" else (" message = '" + message + "',")
|
||||
fail("Illegal value:$msg illegal = '$illegal', actual = '$actual'")
|
||||
val msg = if (message == null) "" else ", message = '$message'"
|
||||
fail("Illegal value: illegal = '$illegal', actual = '$actual'$msg")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> assertSame(expected: T, actual: T, message: String? = null) {
|
||||
if (expected !== actual) {
|
||||
val msg = if (message == null) "" else (" message = '" + message + "',")
|
||||
fail("Expected same instances, got expected = '$expected', actual = '$actual'")
|
||||
val msg = if (message == null) "" else ", message = '$message'"
|
||||
fail("Expected same instances: expected = '$expected', actual = '$actual'$msg")
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> assertArrayEquals(expected: Array<out T>, actual: Array<out T>, message: String? = null) {
|
||||
if (!arraysEqual(expected, actual)) {
|
||||
val msg = if (message == null) "" else (" message = '" + message + "',")
|
||||
fail("Unexpected array:$msg expected = '$expected', actual = '$actual'")
|
||||
val msg = if (message == null) "" else ", message = '$message'"
|
||||
fail("Unexpected array: expected = '$expected', actual = '$actual'$msg")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user