implement better this aliasing, implement anti shadowing.

This commit is contained in:
Pavel Talanov
2011-12-14 16:42:25 +04:00
parent 75f407cc44
commit 32d96ad1eb
9 changed files with 93 additions and 35 deletions
+18
View File
@@ -0,0 +1,18 @@
<component name="ArtifactManager">
<artifact type="jar" name="k2js:jar">
<output-path>$PROJECT_DIR$/out/artifacts/k2js_jar</output-path>
<root id="archive" name="k2js.jar">
<element id="module-output" name="backend" />
<element id="module-output" name="frontend" />
<element id="module-output" name="frontend.java" />
<element id="module-output" name="stdlib" />
<element id="module-output" name="jetTests" />
<element id="module-output" name="translator" />
<element id="module-output" name="js" />
<element id="extracted-dir" path="$PROJECT_DIR$/translator/lib/js.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/translator/lib/junit-4.10.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/translator/lib/guava-10.0.1.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../../Kotlin/jet/lib/asm-util-3.3.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>
@@ -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<DeclarationDescriptor, JsName> aliases = new HashMap<DeclarationDescriptor, JsName>();
@Nullable
private JsName aliasForThis = null;
private final Map<DeclarationDescriptor, JsName> aliasesForDescriptors = new HashMap<DeclarationDescriptor, JsName>();
@NotNull
private Stack<JsName> thisAliases = new Stack<JsName>();
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());
}
}
@@ -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) {
@@ -27,7 +27,7 @@ public final class TemporaryVariable {
}
@NotNull
/*package*/ JsName name() {
public JsName name() {
return variableName;
}
@@ -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
@@ -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<JsParameter> 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);
}
@@ -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();
}
@@ -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");
}
}
@@ -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;
}