diff --git a/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java b/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java index 5c5f3eb1ec4..12b4bafeb89 100644 --- a/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/declaration/ClassDeclarationTranslator.java @@ -4,12 +4,14 @@ import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetNamespace; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.TranslationContext; +import org.jetbrains.k2js.translate.utils.BindingUtils; import org.jetbrains.k2js.translate.utils.Namer; import org.jetbrains.k2js.utils.ClassSorter; @@ -95,7 +97,8 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { private void removeAliases() { for (JetClass jetClass : getClassDeclarations()) { - context().aliaser().removeAliasForDeclaration(jetClass); + ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context().bindingContext(), jetClass); + context().aliaser().removeAliasForDescriptor(descriptor); } } @@ -118,11 +121,13 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { return AstUtil.newVar(localClassName, classDeclarationExpression); } + @NotNull private JsName generateLocalAlias(@NotNull JetClass declaration) { JsName globalClassName = context().getNameForElement(declaration); JsName localAlias = dummyFunctionScope.declareName(globalClassName.getIdent()); localToGlobalClassName.put(localAlias, globalClassName); - context().aliaser().setAliasForDeclaration(declaration, localAlias); + ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context().bindingContext(), declaration); + context().aliaser().setAliasForDescriptor(descriptor, localAlias); return localAlias; } } diff --git a/translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java index 8c0ae7a2f6f..f896f3aa367 100644 --- a/translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/declaration/ClassTranslator.java @@ -16,7 +16,6 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.TranslationContext; import org.jetbrains.k2js.translate.utils.BindingUtils; -import org.jetbrains.k2js.translate.utils.Namer; import java.util.ArrayList; import java.util.List; @@ -53,9 +52,9 @@ public final class ClassTranslator extends AbstractTranslator { @NotNull private JsInvocation classCreateMethodInvocation() { if (classDeclaration.isTrait()) { - return AstUtil.newInvocation(Namer.traitCreationMethodReference()); + return AstUtil.newInvocation(context().namer().traitCreationMethodReference()); } else { - return AstUtil.newInvocation(Namer.classCreationMethodReference()); + return AstUtil.newInvocation(context().namer().classCreationMethodReference()); } } @@ -102,8 +101,7 @@ public final class ClassTranslator extends AbstractTranslator { private JsNameRef getClassReference(@NotNull ClassDescriptor superClassDescriptor) { //TODO we actually know that in current implementation superclass must have an alias but // if future it might change - return context().aliaser().getAliasForDeclaration( - BindingUtils.getClassForDescriptor(context().bindingContext(), superClassDescriptor)); + return context().aliaser().getAliasForDeclaration(superClassDescriptor); } @Nullable diff --git a/translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java b/translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java index 513543e998b..3739e32e73b 100644 --- a/translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/declaration/NamespaceTranslator.java @@ -57,7 +57,7 @@ public final class NamespaceTranslator extends AbstractTranslator { @NotNull private JsInvocation namespaceCreateMethodInvocation() { - return AstUtil.newInvocation(Namer.namespaceCreationMethodReference()); + return AstUtil.newInvocation(context().namer().namespaceCreationMethodReference()); } @NotNull diff --git a/translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java b/translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java index 9728e173a9b..5c7bf37ecf7 100644 --- a/translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/expression/PatternTranslator.java @@ -12,7 +12,6 @@ import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.translate.general.TranslationContext; import org.jetbrains.k2js.translate.utils.BindingUtils; -import org.jetbrains.k2js.translate.utils.Namer; import org.jetbrains.k2js.translate.utils.TranslationUtils; /** @@ -62,7 +61,7 @@ public final class PatternTranslator extends AbstractTranslator { private JsExpression translateTypePattern(@NotNull JsExpression expressionToMatch, @NotNull JetTypePattern pattern) { - JsInvocation isCheck = AstUtil.newInvocation(Namer.isOperationReference(), + JsInvocation isCheck = AstUtil.newInvocation(context().namer().isOperationReference(), expressionToMatch, getClassReference(pattern)); if (isNullable(pattern)) { return addNullCheck(expressionToMatch, isCheck); diff --git a/translator/src/org/jetbrains/k2js/translate/general/Aliaser.java b/translator/src/org/jetbrains/k2js/translate/general/Aliaser.java index 8a32880c612..6abe2f143f2 100644 --- a/translator/src/org/jetbrains/k2js/translate/general/Aliaser.java +++ b/translator/src/org/jetbrains/k2js/translate/general/Aliaser.java @@ -4,18 +4,26 @@ 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.psi.JetDeclaration; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import java.util.HashMap; import java.util.Map; public class Aliaser { + + static public Aliaser aliasesForStandardClasses() { + Aliaser result = new Aliaser(); + //result.setAliasForDescriptor(); + return result; + } + + @NotNull - private final Map aliases = new HashMap(); + private final Map aliases = new HashMap(); @Nullable private JsName aliasForThis = null; - public Aliaser() { + private Aliaser() { } @NotNull @@ -36,23 +44,23 @@ public class Aliaser { return (aliasForThis != null); } - public boolean hasAliasForDeclaration(@NotNull JetDeclaration declaration) { + public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { return aliases.containsKey(declaration); } @NotNull - public JsNameRef getAliasForDeclaration(@NotNull JetDeclaration declaration) { + public JsNameRef getAliasForDeclaration(@NotNull DeclarationDescriptor declaration) { JsName alias = aliases.get(declaration); assert alias != null : "Use has alias for declaration to check."; return alias.makeRef(); } - public void setAliasForDeclaration(@NotNull JetDeclaration declaration, @NotNull JsName alias) { + public void setAliasForDescriptor(@NotNull DeclarationDescriptor declaration, @NotNull JsName alias) { assert (!hasAliasForDeclaration(declaration)) : "This declaration already has an alias!"; aliases.put(declaration, alias); } - public void removeAliasForDeclaration(@NotNull JetDeclaration declaration) { + public void removeAliasForDescriptor(@NotNull DeclarationDescriptor declaration) { assert (hasAliasForDeclaration(declaration)) : "This declaration does not has an alias!"; aliases.remove(declaration); } diff --git a/translator/src/org/jetbrains/k2js/translate/general/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/general/TranslationContext.java index d3e5d003366..61093fb6213 100644 --- a/translator/src/org/jetbrains/k2js/translate/general/TranslationContext.java +++ b/translator/src/org/jetbrains/k2js/translate/general/TranslationContext.java @@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.declarations.Declarations; import org.jetbrains.k2js.translate.utils.BindingUtils; +import org.jetbrains.k2js.translate.utils.Namer; /** * @author Talanov Pavel @@ -40,7 +41,7 @@ public final class TranslationContext { JsScope rootScope = program.getRootScope(); Scopes scopes = new Scopes(rootScope, rootScope, rootScope); return new TranslationContext(null, program, bindingContext, - scopes, extractor, new Aliaser()); + scopes, extractor, Aliaser.aliasesForStandardClasses(), Namer.newInstance(rootScope)); } @NotNull @@ -55,17 +56,21 @@ public final class TranslationContext { private final Declarations declarations; @NotNull private final Aliaser aliaser; + @NotNull + private final Namer namer; private TranslationContext(@Nullable JsName namespaceName, @NotNull JsProgram program, @NotNull BindingContext bindingContext, @NotNull Scopes scopes, - @NotNull Declarations declarations, @NotNull Aliaser aliaser) { + @NotNull Declarations declarations, @NotNull Aliaser aliaser, + @NotNull Namer namer) { this.program = program; this.bindingContext = bindingContext; this.namespaceName = namespaceName; this.scopes = scopes; this.declarations = declarations; this.aliaser = aliaser; + this.namer = namer; } @NotNull @@ -79,7 +84,7 @@ public final class TranslationContext { JsName namespaceName = getNameForDescriptor(descriptor); Scopes newScopes = new Scopes(namespaceScope, namespaceScope, namespaceScope); return new TranslationContext(namespaceName, program, bindingContext, newScopes, - declarations, new Aliaser()); + declarations, aliaser, namer); } @NotNull @@ -92,7 +97,7 @@ public final class TranslationContext { JsScope classScope = declarations.getScope(descriptor); Scopes newScopes = new Scopes(classScope, classScope, scopes.namespaceScope); return new TranslationContext(namespaceName, program, bindingContext, - newScopes, declarations, aliaser); + newScopes, declarations, aliaser, namer); } @NotNull @@ -115,26 +120,21 @@ public final class TranslationContext { JsScope functionScope = declarations.getScope(descriptor); Scopes newScopes = new Scopes(functionScope, scopes.classScope, scopes.namespaceScope); return new TranslationContext(namespaceName, program, bindingContext, - newScopes, declarations, aliaser); + newScopes, declarations, aliaser, namer); } -// @NotNull TranslationContext newAliases(Map newAliases) { -// Map aliases = new HashMap(this.aliases); -// aliases.putAll(newAliases); -// return new TranslationContext(namespaceName, program, bindingContext, scopes, declarations, aliases); -// } - // Note: Should be used if and only if scope has no corresponding descriptor @NotNull public TranslationContext newEnclosingScope(@NotNull JsScope enclosingScope) { Scopes newScopes = new Scopes(enclosingScope, scopes.classScope, scopes.namespaceScope); return new TranslationContext(namespaceName, program, bindingContext, - newScopes, declarations, aliaser); + newScopes, declarations, aliaser, namer); } + //TODO: move to namer @NotNull - public JsNameRef getNamespaceQualifiedReference(JsName name) { + public JsNameRef getNamespaceQualifiedReference(@NotNull JsName name) { if (namespaceName != null) { return AstUtil.newNameRef(namespaceName.makeRef(), name); } @@ -200,7 +200,13 @@ public final class TranslationContext { return declarations.isDeclared(descriptor); } + @NotNull public Aliaser aliaser() { return aliaser; } + + @NotNull + public Namer namer() { + return namer; + } } diff --git a/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java b/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java index 1291d6fadaf..30797b50a08 100644 --- a/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java @@ -35,7 +35,7 @@ public abstract class AbstractInitializerTranslator extends AbstractTranslator { @NotNull public JsPropertyInitializer generateInitializeMethod() { JsPropertyInitializer initializer = new JsPropertyInitializer(); - initializer.setLabelExpr(context().program().getStringLiteral(Namer.INITIALIZE_METHOD_NAME)); + initializer.setLabelExpr(Namer.initializeMethodReference()); initializer.setValueExpr(generateInitializerFunction()); return initializer; } diff --git a/translator/src/org/jetbrains/k2js/translate/operation/OperatorTable.java b/translator/src/org/jetbrains/k2js/translate/operation/OperatorTable.java index 6501349a548..cb3af9534fb 100644 --- a/translator/src/org/jetbrains/k2js/translate/operation/OperatorTable.java +++ b/translator/src/org/jetbrains/k2js/translate/operation/OperatorTable.java @@ -8,7 +8,6 @@ import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.k2js.translate.utils.Namer; import java.util.HashMap; import java.util.Map; @@ -52,8 +51,9 @@ public final class OperatorTable { binaryOperatorsMap.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD); } + //TODO: resolve static { - operatorToFunctionNameReference.put(JetTokens.IS_KEYWORD, Namer.isOperationReference()); + //operatorToFunctionNameReference.put(JetTokens.IS_KEYWORD, Namer.isOperationReference()); } public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) { diff --git a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java index 1599361e0f1..5ac229be92e 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/ReferenceTranslator.java @@ -7,7 +7,6 @@ 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 org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.k2js.translate.general.AbstractTranslator; import org.jetbrains.k2js.translate.general.Translation; @@ -55,15 +54,11 @@ public class ReferenceTranslator extends AbstractTranslator { BindingUtils.getDescriptorForReferenceExpression(context().bindingContext(), expression); if (referencedDescriptor == null) return null; - JetDeclaration declaration = - BindingUtils.getDeclarationForDescriptor(context().bindingContext(), referencedDescriptor); - if (declaration == null) return null; - - if (!context().aliaser().hasAliasForDeclaration(declaration)) { + if (!context().aliaser().hasAliasForDeclaration(referencedDescriptor)) { return null; } - return context().aliaser().getAliasForDeclaration(declaration); + return context().aliaser().getAliasForDeclaration(referencedDescriptor); } @Nullable diff --git a/translator/src/org/jetbrains/k2js/translate/utils/Namer.java b/translator/src/org/jetbrains/k2js/translate/utils/Namer.java index 82fd9e373de..903f1c78617 100644 --- a/translator/src/org/jetbrains/k2js/translate/utils/Namer.java +++ b/translator/src/org/jetbrains/k2js/translate/utils/Namer.java @@ -1,33 +1,46 @@ package org.jetbrains.k2js.translate.utils; +import com.google.dart.compiler.backend.js.ast.JsName; import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.backend.js.ast.JsScope; import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; /** * @author Talanov Pavel */ /* - * This class is a complete dummy and should completely change in the future + * This class is a dummy and should completely change in the future */ +//TODO: rework into stateful class and include into context + public final class Namer { - private Namer() { - - } - - public static final String INITIALIZE_METHOD_NAME = "initialize"; + private static final String INITIALIZE_METHOD_NAME = "initialize"; private static final String CLASS_OBJECT_NAME = "Class"; - //private static final String CLASS_CREATE_METHOD_NAME = "create"; + private static final String TRAIT_OBJECT_NAME = "Trait"; + private static final String NAMESPACE_OBJECT_NAME = "Namespace"; private static final String SETTER_PREFIX = "set_"; private static final String GETTER_PREFIX = "get_"; private static final String BACKING_FIELD_PREFIX = "$"; + // TODO: work on the unified approach to string constants public static final String SUPER_METHOD_NAME = "super_init"; - // public static final String DEFAULT_SETTER_PARAM_NAME = "val"; + private static final String KOTLIN_OBJECT_NAME = "Kotlin"; - public static String getClassObjectName() { - //TODO dummy representation - return CLASS_OBJECT_NAME; + @NotNull + public static JsNameRef initializeMethodReference() { + return AstUtil.newQualifiedNameRef(INITIALIZE_METHOD_NAME); + } + + @NotNull + public static JsNameRef superMethodReference() { + return AstUtil.newQualifiedNameRef(SUPER_METHOD_NAME); + } + + @NotNull + public static String nameForClassesVariable() { + return "classes"; } public static String getNameForAccessor(String propertyName, boolean isGetter) { @@ -54,38 +67,61 @@ public final class Namer { return prefix + name; } - public static String getNameForNamespace(String name) { - return name; + public static Namer newInstance(@NotNull JsScope rootScope) { + return new Namer(rootScope); } - //TODO: dummy - public static JsNameRef classObjectReference() { - return AstUtil.newQualifiedNameRef("Class"); + @NotNull + private final JsName kotlinName; + @NotNull + private final JsScope kotlinScope; + @NotNull + private final JsName className; + @NotNull + private final JsName traitName; + @NotNull + private final JsName namespaceName; + + private Namer(@NotNull JsScope rootScope) { + kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME); + kotlinScope = new JsScope(rootScope, "Kotlin standard object"); + traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME); + namespaceName = kotlinScope.declareName(NAMESPACE_OBJECT_NAME); + className = kotlinScope.declareName(CLASS_OBJECT_NAME); } - public static JsNameRef classCreationMethodReference() { - return AstUtil.newQualifiedNameRef("Class.create"); + @NotNull + public JsNameRef classCreationMethodReference() { + return kotlin(createMethodReference(className)); } - public static JsNameRef traitCreationMethodReference() { - return AstUtil.newQualifiedNameRef("Trait.create"); + @NotNull + public JsNameRef traitCreationMethodReference() { + return kotlin(createMethodReference(traitName)); } - public static JsNameRef namespaceCreationMethodReference() { - return AstUtil.newQualifiedNameRef("Namespace.create"); + @NotNull + public JsNameRef namespaceCreationMethodReference() { + return kotlin(createMethodReference(namespaceName)); } - public static JsNameRef isOperationReference() { - return AstUtil.newQualifiedNameRef("isType"); + @NotNull + private JsNameRef createMethodReference(@NotNull JsName name) { + JsNameRef qualifier = name.makeRef(); + JsNameRef reference = AstUtil.newQualifiedNameRef("create"); + AstUtil.setQualifier(reference, qualifier); + return reference; } - public static JsNameRef initializeMethodReference() { - return AstUtil.newQualifiedNameRef("initialize"); + @NotNull + private JsNameRef kotlin(@NotNull JsNameRef reference) { + JsNameRef kotlinReference = kotlinName.makeRef(); + AstUtil.setQualifier(reference, kotlinReference); + return reference; } - public static String nameForClassesVariable() { - return "classes"; + @NotNull + public JsNameRef isOperationReference() { + return kotlin(AstUtil.newQualifiedNameRef("isType")); } - - } diff --git a/translator/test/org/jetbrains/k2js/test/StandardClassesTest.java b/translator/test/org/jetbrains/k2js/test/StandardClassesTest.java new file mode 100644 index 00000000000..6ac28bbcfd9 --- /dev/null +++ b/translator/test/org/jetbrains/k2js/test/StandardClassesTest.java @@ -0,0 +1,20 @@ +package org.jetbrains.k2js.test; + +import org.junit.Test; + +/** + * @author Talanov Pavel + */ +public class StandardClassesTest extends TranslationTest { + final private static String MAIN = "standardClasses/"; + + @Override + protected String mainDirectory() { + return MAIN; + } + + @Test + public void array() throws Exception { + testFooBoxIsTrue("array.kt"); + } +} diff --git a/translator/testFiles/kotlin_lib.js b/translator/testFiles/kotlin_lib.js index ae573cc5c22..ed0bf3a6f24 100644 --- a/translator/testFiles/kotlin_lib.js +++ b/translator/testFiles/kotlin_lib.js @@ -458,3 +458,8 @@ Kotlin.Array = Class.create({ this.array[index] = value; } }) + +Kotlin.Class = Class +Kotlin.Namespace = Namespace +Kotlin.Trait = Trait +Kotlin.isType = isType diff --git a/translator/testFiles/standardClasses/cases/array.kt b/translator/testFiles/standardClasses/cases/array.kt new file mode 100644 index 00000000000..90eae66d488 --- /dev/null +++ b/translator/testFiles/standardClasses/cases/array.kt @@ -0,0 +1,9 @@ +namespace foo + +fun box() : Boolean { + + val a = Array(2) + a.set(1, 2) + return a.get(1) == 2 +} +