From 32d96ad1ebf236c99741167a261489fb35056417 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Wed, 14 Dec 2011 16:42:25 +0400 Subject: [PATCH] implement better this aliasing, implement anti shadowing. --- .idea/artifacts/k2js_jar.xml | 18 ++++++++++ .../k2js/translate/context/Aliaser.java | 33 ++++++++++--------- .../translate/context/StandardClasses.java | 8 +++-- .../translate/context/TemporaryVariable.java | 2 +- .../translate/context/TranslationContext.java | 6 ++-- .../expression/FunctionTranslator.java | 28 ++++++++-------- .../k2js/translate/general/Translation.java | 6 ++++ .../k2js/test/ExtensionFunctionTest.java | 5 +++ .../cases/extensionInsideFunctionLiteral.kt | 22 +++++++++++++ 9 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 .idea/artifacts/k2js_jar.xml create mode 100644 translator/testFiles/extensionFunction/cases/extensionInsideFunctionLiteral.kt diff --git a/.idea/artifacts/k2js_jar.xml b/.idea/artifacts/k2js_jar.xml new file mode 100644 index 00000000000..c80e2b9b132 --- /dev/null +++ b/.idea/artifacts/k2js_jar.xml @@ -0,0 +1,18 @@ + + + $PROJECT_DIR$/out/artifacts/k2js_jar + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/context/Aliaser.java b/translator/src/org/jetbrains/k2js/translate/context/Aliaser.java index 13059a924d4..8d48863ac3e 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/Aliaser.java +++ b/translator/src/org/jetbrains/k2js/translate/context/Aliaser.java @@ -3,13 +3,13 @@ package org.jetbrains.k2js.translate.context; import com.google.dart.compiler.backend.js.ast.JsName; import com.google.dart.compiler.backend.js.ast.JsNameRef; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import java.util.HashMap; import java.util.Map; +import java.util.Stack; -//TODO: implement aliases stack for this need TESTS +//TODO: implement aliasesForDescriptors stack for this need TESTS public class Aliaser { public static Aliaser newInstance() { @@ -17,50 +17,53 @@ public class Aliaser { } @NotNull - private final Map aliases = new HashMap(); - @Nullable - private JsName aliasForThis = null; + private final Map aliasesForDescriptors = new HashMap(); + @NotNull + private Stack thisAliases = new Stack(); private Aliaser() { } @NotNull public JsNameRef getAliasForThis() { - assert aliasForThis != null : "Alias is null. Use hasAliasForThis function to check."; - return aliasForThis.makeRef(); + assert !thisAliases.empty() : "No alias. Use hasAliasForThis function to check."; + return thisAliases.peek().makeRef(); } @SuppressWarnings("NullableProblems") public void setAliasForThis(@NotNull JsName alias) { - aliasForThis = alias; + thisAliases.push(alias); } - public void removeAliasForThis() { - aliasForThis = null; + //NOTE: here we are passing alias to check that they are set and removed in consistent order. + public void removeAliasForThis(@NotNull JsName aliasToRemove) { + assert !thisAliases.empty() : "Error: removing alias, when it is not set."; + JsName lastAlias = thisAliases.pop(); + assert lastAlias.equals(aliasToRemove) : "Error: inconsistent alias removing."; } public boolean hasAliasForThis() { - return (aliasForThis != null); + return (!thisAliases.empty()); } public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { - return aliases.containsKey(declaration.getOriginal()); + return aliasesForDescriptors.containsKey(declaration.getOriginal()); } @NotNull public JsName getAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { - JsName alias = aliases.get(declaration.getOriginal()); + JsName alias = aliasesForDescriptors.get(declaration.getOriginal()); assert alias != null : "Use has alias for declaration to check."; return alias; } public void setAliasForDescriptor(@NotNull DeclarationDescriptor declaration, @NotNull JsName alias) { assert (!hasAliasForDeclaration(declaration.getOriginal())) : "This declaration already has an alias!"; - aliases.put(declaration.getOriginal(), alias); + aliasesForDescriptors.put(declaration.getOriginal(), alias); } public void removeAliasForDescriptor(@NotNull DeclarationDescriptor declaration) { assert (hasAliasForDeclaration(declaration.getOriginal())) : "This declaration does not has an alias!"; - aliases.remove(declaration.getOriginal()); + aliasesForDescriptors.remove(declaration.getOriginal()); } } \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java index 393efa9faef..336de4d56da 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java +++ b/translator/src/org/jetbrains/k2js/translate/context/StandardClasses.java @@ -128,7 +128,9 @@ public final class StandardClasses { } private void declareStandardTopLevelObject(@NotNull String fullQualifiedName, @NotNull String kotlinLibName) { - nameMap.put(fullQualifiedName, kotlinScope.declareName(kotlinLibName)); + JsName declaredName = kotlinScope.declareName(kotlinLibName); + declaredName.setObfuscatable(false); + nameMap.put(fullQualifiedName, declaredName); scopeMap.put(fullQualifiedName, new JsScope(kotlinScope, "standard object " + kotlinLibName)); } @@ -143,7 +145,9 @@ public final class StandardClasses { @NotNull String kotlinLibName) { JsScope classScope = scopeMap.get(fullQualifiedClassName); String fullQualifiedMethodName = fullQualifiedClassName + "." + shortMethodName; - nameMap.put(fullQualifiedMethodName, classScope.declareName(kotlinLibName)); + JsName declaredName = classScope.declareName(kotlinLibName); + declaredName.setObfuscatable(false); + nameMap.put(fullQualifiedMethodName, declaredName); } public boolean isStandardObject(@NotNull DeclarationDescriptor descriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java b/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java index 59adc6780fc..acacd981de1 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java +++ b/translator/src/org/jetbrains/k2js/translate/context/TemporaryVariable.java @@ -27,7 +27,7 @@ public final class TemporaryVariable { } @NotNull - /*package*/ JsName name() { + public JsName name() { return variableName; } diff --git a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java index c8f630b2333..98736c5a35f 100644 --- a/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java +++ b/translator/src/org/jetbrains/k2js/translate/context/TranslationContext.java @@ -157,13 +157,13 @@ public final class TranslationContext { @NotNull public TemporaryVariable newAliasForThis() { - TemporaryVariable aliasForThis = dynamicContext.declareTemporaryWithName("that", new JsThisRef()); + TemporaryVariable aliasForThis = dynamicContext.declareTemporary(new JsThisRef()); aliaser().setAliasForThis(aliasForThis.name()); return aliasForThis; } - public void removeAliasForThis() { - aliaser().removeAliasForThis(); + public void removeAliasForThis(@NotNull JsName aliasToRemove) { + aliaser().removeAliasForThis(aliasToRemove); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java index 22997d2e730..0f00c5f2710 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/FunctionTranslator.java @@ -25,6 +25,15 @@ import static org.jetbrains.k2js.translate.utils.TranslationUtils.functionWithSc */ public final class FunctionTranslator extends AbstractTranslator { + @NotNull + public static FunctionTranslator newInstance(@NotNull JetDeclarationWithBody function, + @NotNull TranslationContext context) { + return new FunctionTranslator(function, context); + } + + //TODO: implement more generic and safe way + private static final String RECEIVER_PARAMETER_NAME = "receiver"; + @NotNull private final JetDeclarationWithBody functionDeclaration; @NotNull @@ -32,11 +41,6 @@ public final class FunctionTranslator extends AbstractTranslator { @NotNull private final TranslationContext functionBodyContext; - @NotNull - public static FunctionTranslator newInstance(@NotNull JetDeclarationWithBody function, - @NotNull TranslationContext context) { - return new FunctionTranslator(function, context); - } private FunctionTranslator(@NotNull JetDeclarationWithBody functionDeclaration, @NotNull TranslationContext context) { @@ -58,7 +62,7 @@ public final class FunctionTranslator extends AbstractTranslator { public JsExpression translateAsLiteral() { TemporaryVariable aliasForThis = context().newAliasForThis(); JsFunction function = generateFunctionObject(); - context().removeAliasForThis(); + context().removeAliasForThis(aliasForThis.name()); return AstUtil.newSequence(aliasForThis.assignmentExpression(), function); } @@ -72,7 +76,8 @@ public final class FunctionTranslator extends AbstractTranslator { private void restoreContext() { if (isExtensionFunction()) { - functionBodyContext.removeAliasForThis(); + JsName receiverAlias = functionBodyContext.jsScope().findExistingName(RECEIVER_PARAMETER_NAME); + functionBodyContext.removeAliasForThis(receiverAlias); } } @@ -165,19 +170,14 @@ public final class FunctionTranslator extends AbstractTranslator { } private void mayBeAddThisParameterForExtensionFunction(@NotNull List jsParameters) { - boolean isExtensionFunction = isExtensionFunction(); - if (isExtensionFunction) { - JsName receiver = functionBodyContext.jsScope().declareName("receiver"); + if (isExtensionFunction()) { + JsName receiver = functionBodyContext.jsScope().declareName(RECEIVER_PARAMETER_NAME); context().aliaser().setAliasForThis(receiver); jsParameters.add(new JsParameter(receiver)); } } private boolean isExtensionFunction() { -// if (!(functionDeclaration instanceof JetNamedFunction)) { -// return false; -// } - FunctionDescriptor functionDescriptor = getFunctionDescriptor(context().bindingContext(), functionDeclaration); return DescriptorUtils.isExtensionFunction(functionDescriptor); } diff --git a/translator/src/org/jetbrains/k2js/translate/general/Translation.java b/translator/src/org/jetbrains/k2js/translate/general/Translation.java index ce2a390b98d..8b6609582a0 100644 --- a/translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -1,5 +1,7 @@ package org.jetbrains.k2js.translate.general; +import com.google.dart.compiler.backend.js.JsNamer; +import com.google.dart.compiler.backend.js.JsPrettyNamer; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import com.intellij.openapi.project.Project; @@ -98,6 +100,10 @@ public final class Translation { JsBlock block = staticContext.getProgram().getFragmentBlock(0); TranslationContext context = TranslationContext.rootContext(staticContext); block.addStatement(Translation.translateNamespace(namespace, context)); + + JsNamer namer = new JsPrettyNamer(); + namer.exec(context.program()); + return context.program(); } diff --git a/translator/test/org/jetbrains/k2js/test/ExtensionFunctionTest.java b/translator/test/org/jetbrains/k2js/test/ExtensionFunctionTest.java index 040555e9de7..c6855d5e876 100644 --- a/translator/test/org/jetbrains/k2js/test/ExtensionFunctionTest.java +++ b/translator/test/org/jetbrains/k2js/test/ExtensionFunctionTest.java @@ -47,4 +47,9 @@ public final class ExtensionFunctionTest extends TranslationTest { public void extensionLiteralPassedToFunction() throws Exception { testFooBoxIsTrue("extensionLiteralPassedToFunction.kt"); } + + @Test + public void extensionInsideFunctionLiteral() throws Exception { + testFooBoxIsTrue("extensionInsideFunctionLiteral.kt"); + } } diff --git a/translator/testFiles/extensionFunction/cases/extensionInsideFunctionLiteral.kt b/translator/testFiles/extensionFunction/cases/extensionInsideFunctionLiteral.kt new file mode 100644 index 00000000000..26d2a07b437 --- /dev/null +++ b/translator/testFiles/extensionFunction/cases/extensionInsideFunctionLiteral.kt @@ -0,0 +1,22 @@ +namespace foo + +class M() { + var m = 0 + + fun eval() { + var d = { + var c = {Int.() => this + 3} + m += 3.c() + } + d(); + } +} + +fun box() : Boolean { + var a = M() + if (a.m != 0) return false; + a.eval() + if (a.m != 6) return false; + + return true; +} \ No newline at end of file