diff --git a/.idea/workspace.xml b/.idea/workspace.xml index b94cfd992c5..904c85c1d44 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -8,11 +8,25 @@ - - + + + + + + + - - + + + + + + + + + + + @@ -110,7 +124,7 @@ - + @@ -131,10 +145,10 @@ - + - + @@ -153,80 +167,17 @@ - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -234,10 +185,75 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -264,22 +280,22 @@ @@ -411,68 +427,6 @@ @@ -1051,110 +1105,122 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java index 738d12aa0d1..c2da93681a1 100644 --- a/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/BinaryOperationTranslator.java @@ -39,7 +39,7 @@ public final class BinaryOperationTranslator extends OperationTranslator { this.isVariableReassignment = isVariableReassignment(expression); this.operationReference = getOverloadedOperationReference(expression.getOperationReference()); this.right = translateRightExpression(); - //TODO: decide whether it is harmful to possibly translate left expression more than once + //TODO: decide whether it is harmful to possibly translateNamespace left expression more than once this.left = translateLeftExpression(); } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java index 948669f08ba..d45b6df363d 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java @@ -106,7 +106,7 @@ public final class ClassDeclarationTranslator extends AbstractTranslator { JsName localClassName = dummyFunctionScope.declareName(globalClassName.getIdent()); localToGlobalClassName.put(localClassName, globalClassName); JsInvocation classDeclarationExpression = - Translation.classTranslator(translationContext()).translateClass(declaration); + Translation.translateClassDeclaration(declaration, translationContext()); return AstUtil.newVar(localClassName, classDeclarationExpression); } } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java deleted file mode 100644 index 95502588c0a..00000000000 --- a/translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.jetbrains.k2js.translate; - -import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.util.AstUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.*; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Talanov Pavel - */ -public final class ClassInitializerVisitor extends AbstractInitializerVisitor { - - @NotNull - private final JetClass classDeclaration; - - public ClassInitializerVisitor(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { - super(context, new JsScope(context.getScopeForElement(classDeclaration), - "initializer " + classDeclaration.getName())); - this.classDeclaration = classDeclaration; - } - - @Override - @NotNull - public JsFunction generate() { - JsFunction result = JsFunction.getAnonymousFunctionWithScope(initializerMethodScope); - result.setParameters(translatePrimaryConstructorParameters(classDeclaration)); - result.setBody(generateInitializerMethodBody(classDeclaration, initializerMethodContext)); - return result; - } - - @NotNull - private JsBlock generateInitializerMethodBody(@NotNull JetClass classDeclaration, - @NotNull TranslationContext context) { - - List initializerStatements = generateCallToSuperMethod(classDeclaration, context); - initializerStatements.addAll(classDeclaration.accept(this, context)); - return AstUtil.newBlock(initializerStatements); - } - - @NotNull - private List generateCallToSuperMethod(@NotNull JetClass classDeclaration, - @NotNull TranslationContext context) { - List result = new ArrayList(); - if (BindingUtils.hasAncestorClass(context.bindingContext(), classDeclaration)) { - JsName superMethodName = initializerMethodScope.declareName(Namer.SUPER_METHOD_NAME); - List arguments = translateArguments(classDeclaration, context); - result.add(AstUtil.convertToStatement - (AstUtil.newInvocation(AstUtil.thisQualifiedReference(superMethodName), arguments))); - } - return result; - } - - @NotNull - private List translateArguments(@NotNull JetClass classDeclaration, - @NotNull TranslationContext context) { - JetDelegatorToSuperCall superCall = getSuperCall(classDeclaration); - return translateArgumentList(superCall.getValueArguments(), context); - } - - @NotNull - private JetDelegatorToSuperCall getSuperCall(@NotNull JetClass classDeclaration) { - JetDelegatorToSuperCall result = null; - for (JetDelegationSpecifier specifier : classDeclaration.getDelegationSpecifiers()) { - if (specifier instanceof JetDelegatorToSuperCall) { - result = (JetDelegatorToSuperCall) specifier; - } - } - assert result != null : "Class must call ancestor's constructor."; - return result; - } - - @Override - @NotNull - public List visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - List initializerStatements = new ArrayList(); - for (JetDeclaration declaration : expression.getDeclarations()) { - initializerStatements.addAll(declaration.accept(this, context)); - } - return initializerStatements; - } - - @NotNull - List translatePrimaryConstructorParameters(@NotNull JetClass expression) { - List result = new ArrayList(); - List parameters = expression.getPrimaryConstructorParameters(); - for (JetParameter parameter : parameters) { - JsName parameterName = initializerMethodScope.declareName(parameter.getName()); - result.add(new JsParameter(parameterName)); - } - return result; - } -} diff --git a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java index 22c6e54cbe2..8451d47a55d 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java @@ -25,46 +25,48 @@ public final class ClassTranslator extends AbstractTranslator { private final DeclarationBodyVisitor declarationBodyVisitor = new DeclarationBodyVisitor(); @NotNull - public static ClassTranslator newInstance(@NotNull TranslationContext context) { - return new ClassTranslator(context); + private final JetClass classDeclaration; + + @NotNull + static public JsInvocation translateClass(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { + return (new ClassTranslator(classDeclaration, context)).translateClass(); } - private ClassTranslator(TranslationContext context) { - super(context); + private ClassTranslator(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { + super(context.newClass(classDeclaration)); + this.classDeclaration = classDeclaration; } @NotNull - public JsInvocation translateClass(@NotNull JetClass jetClassDeclaration) { - JsInvocation jsClassDeclaration = classCreateMethodInvocation(jetClassDeclaration); - addSuperclassReferences(jetClassDeclaration, jsClassDeclaration); - addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration); + private JsInvocation translateClass() { + JsInvocation jsClassDeclaration = classCreateMethodInvocation(); + addSuperclassReferences(jsClassDeclaration); + addClassOwnDeclarations(jsClassDeclaration); return jsClassDeclaration; } @NotNull - private JsInvocation classCreateMethodInvocation(@NotNull JetClass jetClassDeclaration) { - if (jetClassDeclaration.isTrait()) { + private JsInvocation classCreateMethodInvocation() { + if (classDeclaration.isTrait()) { return AstUtil.newInvocation(Namer.traitCreationMethodReference()); } else { return AstUtil.newInvocation(Namer.classCreationMethodReference()); } } - private void addClassOwnDeclarations(@NotNull JetClass classDeclaration, - @NotNull JsInvocation jsClassDeclaration) { - JsObjectLiteral jsClassDescription = translateClassDeclarations(classDeclaration); + private void addClassOwnDeclarations(@NotNull JsInvocation jsClassDeclaration) { + JsObjectLiteral jsClassDescription = translateClassDeclarations(); jsClassDeclaration.getArguments().add(jsClassDescription); } - private void addSuperclassReferences(@NotNull JetClass classDeclaration, - @NotNull JsInvocation jsClassDeclaration) { - for (JsNameRef superClassReference : getSuperclassNameReferences(classDeclaration)) { + private void addSuperclassReferences(@NotNull JsInvocation jsClassDeclaration) { + for (JsNameRef superClassReference : getSuperclassNameReferences()) { jsClassDeclaration.getArguments().add(superClassReference); } } @NotNull - private List getSuperclassNameReferences(@NotNull JetClass classDeclaration) { + private List getSuperclassNameReferences() { List superclassReferences = new ArrayList(); List superclassDescriptors = BindingUtils.getSuperclassDescriptors(translationContext().bindingContext(), classDeclaration); @@ -106,13 +108,13 @@ public final class ClassTranslator extends AbstractTranslator { } @NotNull - private JsObjectLiteral translateClassDeclarations(@NotNull JetClass classDeclaration) { + private JsObjectLiteral translateClassDeclarations() { List propertyList = new ArrayList(); if (!classDeclaration.isTrait()) { - propertyList.add(InitializerGenerator.generateInitializeMethod(classDeclaration, translationContext())); + propertyList.add(Translation.generateClassInitializerMethod(classDeclaration, translationContext())); } propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, - translationContext().newClass(classDeclaration))); + translationContext())); return new JsObjectLiteral(propertyList); } } diff --git a/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java b/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java index 082e6628d2b..9506dbba43c 100644 --- a/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java @@ -41,7 +41,7 @@ public final class DeclarationBodyVisitor extends TranslatorVisitor visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - //TODO: we are interested only in class own declarations + //TODO: return Collections.emptyList(); } diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index c7b051cc1a0..05220de493f 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -103,7 +103,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull public JsNode visitCallExpression(JetCallExpression expression, TranslationContext context) { JsExpression callee = translateCallee(expression, context); - List arguments = translateArgumentList(expression.getValueArguments(), context); + List arguments = TranslationUtils.translateArgumentList(expression.getValueArguments(), context); if (isConstructorInvocation(expression, context)) { JsNew constructorCall = new JsNew(callee); constructorCall.setArguments(arguments); diff --git a/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java b/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java deleted file mode 100644 index c6a4140c269..00000000000 --- a/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.jetbrains.k2js.translate; - -import com.google.dart.compiler.backend.js.ast.JsFunction; -import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetNamedDeclaration; -import org.jetbrains.jet.lang.psi.JetNamespace; - - -//TODO: thing about redesigning this class -public class InitializerGenerator { - - @NotNull - private final TranslationContext context; - @NotNull - private final JetNamedDeclaration declaration; - - static public JsPropertyInitializer generateInitializeMethod(@NotNull JetNamedDeclaration declaration, - @NotNull TranslationContext context) { - return (new InitializerGenerator(context, declaration)).generateInitializeMethod(); - } - - private InitializerGenerator(@NotNull TranslationContext context, @NotNull JetNamedDeclaration declaration) { - this.context = context; - this.declaration = declaration; - assert (declaration instanceof JetClass) || (declaration instanceof JetNamespace) : - "Can create initializers for classes or namespaces only"; - } - - @NotNull - public JsPropertyInitializer generateInitializeMethod() { - JsPropertyInitializer initializer = new JsPropertyInitializer(); - initializer.setLabelExpr(context.program().getStringLiteral(Namer.INITIALIZE_METHOD_NAME)); - initializer.setValueExpr(generateInitializeFunction()); - return initializer; - } - - //TODO: track context change points, make them consistent, make sure that inside class declaration block - // classes reference their ancestor by aliases - @NotNull - private JsFunction generateInitializeFunction() { - AbstractInitializerVisitor visitor; - if (declaration instanceof JetNamespace) { - JetNamespace namespaceDeclaration = (JetNamespace) declaration; - visitor = new NamespaceInitializerVisitor(namespaceDeclaration, - context.newNamespace(namespaceDeclaration)); - } else { - assert declaration instanceof JetClass; - JetClass classDeclaration = (JetClass) declaration; - visitor = new ClassInitializerVisitor(classDeclaration, - context.newClass(classDeclaration)); - } - return visitor.generate(); - } -} \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java index 08836714537..ff2ab48fe13 100644 --- a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java @@ -21,13 +21,12 @@ public final class NamespaceTranslator extends AbstractTranslator { private final ClassDeclarationTranslator classDeclarationTranslator; @NotNull - public static JsStatement translate(@NotNull TranslationContext context, - @NotNull JetNamespace namespace) { - return (new NamespaceTranslator(context, namespace)).translateNamespace(); + public static JsStatement translateNamespace(@NotNull JetNamespace namespace, @NotNull TranslationContext context) { + return (new NamespaceTranslator(namespace, context)).translateNamespace(); } - private NamespaceTranslator(@NotNull TranslationContext context, @NotNull JetNamespace namespace) { - super(context); + private NamespaceTranslator(@NotNull JetNamespace namespace, @NotNull TranslationContext context) { + super(context.newNamespace(namespace)); this.namespace = namespace; this.namespaceName = context.getNameForElement(namespace); this.classDeclarationTranslator = new ClassDeclarationTranslator(context, namespace); @@ -78,9 +77,8 @@ public final class NamespaceTranslator extends AbstractTranslator { @NotNull private JsObjectLiteral translateNamespaceMemberDeclarations() { List propertyList = new ArrayList(); - propertyList.add(InitializerGenerator.generateInitializeMethod(namespace, translationContext())); - propertyList.addAll(new DeclarationBodyVisitor().traverseNamespace(namespace, - translationContext().newNamespace(namespace))); + propertyList.add(Translation.generateNamespaceInitializerMethod(namespace, translationContext())); + propertyList.addAll(new DeclarationBodyVisitor().traverseNamespace(namespace, translationContext())); return new JsObjectLiteral(propertyList); } } diff --git a/translator/src/org/jetbrains/k2js/translate/Translation.java b/translator/src/org/jetbrains/k2js/translate/Translation.java index 1b870236386..3616fcb8473 100644 --- a/translator/src/org/jetbrains/k2js/translate/Translation.java +++ b/translator/src/org/jetbrains/k2js/translate/Translation.java @@ -3,12 +3,11 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetNamespace; -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lang.psi.JetWhenExpression; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.k2js.declarations.Declarations; +import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; +import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator; /** * @author Talanov Pavel @@ -36,12 +35,13 @@ public final class Translation { @NotNull static public JsStatement translateNamespace(@NotNull JetNamespace namespace, @NotNull TranslationContext context) { - return NamespaceTranslator.translate(context, namespace); + return NamespaceTranslator.translateNamespace(namespace, context); } @NotNull - static public ClassTranslator classTranslator(@NotNull TranslationContext context) { - return ClassTranslator.newInstance(context); + static public JsInvocation translateClassDeclaration(@NotNull JetClass classDeclaration, + @NotNull TranslationContext context) { + return ClassTranslator.translateClass(classDeclaration, context); } @NotNull @@ -74,6 +74,18 @@ public final class Translation { return WhenTranslator.translateWhenExpression(expression, context); } + @NotNull + static public JsPropertyInitializer generateClassInitializerMethod(@NotNull JetClass classDeclaration, + @NotNull TranslationContext context) { + return (new ClassInitializerTranslator(classDeclaration, context)).generateInitializeMethod(); + } + + @NotNull + static public JsPropertyInitializer generateNamespaceInitializerMethod(@NotNull JetNamespace namespace, + @NotNull TranslationContext context) { + return (new NamespaceInitializerTranslator(namespace, context)).generateInitializeMethod(); + } + @NotNull static public JsNameRef generateCorrectReference(@NotNull TranslationContext context, @NotNull JetSimpleNameExpression expression, diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationContext.java b/translator/src/org/jetbrains/k2js/translate/TranslationContext.java index 79df53a37ce..938935d5f2b 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslationContext.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslationContext.java @@ -84,7 +84,7 @@ public final class TranslationContext { } @NotNull - TranslationContext newClass(@NotNull JetClass declaration) { + public TranslationContext newClass(@NotNull JetClass declaration) { return newClass(BindingUtils.getClassDescriptor(bindingContext, declaration)); } diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java index 68311099c28..4b87abde5ad 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java @@ -4,7 +4,12 @@ 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.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lang.psi.ValueArgument; + +import java.util.ArrayList; +import java.util.List; /** * @author Talanov Pavel @@ -38,4 +43,26 @@ public final class TranslationUtils { @NotNull String name) { return context.enclosingScope().findExistingName(name); } + + + @NotNull + static public List translateArgumentList(@NotNull List jetArguments, + @NotNull TranslationContext context) { + List jsArguments = new ArrayList(); + for (ValueArgument argument : jetArguments) { + jsArguments.add(translateArgument(context, argument)); + } + return jsArguments; + } + + @NotNull + static public JsExpression translateArgument(@NotNull TranslationContext context, @NotNull ValueArgument argument) { + JetExpression jetExpression = argument.getArgumentExpression(); + if (jetExpression == null) { + throw new AssertionError("Argument with no expression encountered!"); + } + return Translation.translateAsExpression(jetExpression, context); + } + + } diff --git a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java index 0dfd90ca38c..b2560bd85ec 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java @@ -6,10 +6,10 @@ import com.google.dart.compiler.backend.js.ast.JsNameRef; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.*; - -import java.util.ArrayList; -import java.util.List; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.JetVisitor; /** * @author Talanov Pavel @@ -59,23 +59,4 @@ public class TranslatorVisitor extends JetVisitor { } return jsInitExpression; } - - @NotNull - protected List translateArgumentList(@NotNull List jetArguments, - @NotNull TranslationContext context) { - List jsArguments = new ArrayList(); - for (ValueArgument argument : jetArguments) { - jsArguments.add(translateArgument(context, argument)); - } - return jsArguments; - } - - @NotNull - private JsExpression translateArgument(@NotNull TranslationContext context, @NotNull ValueArgument argument) { - JetExpression jetExpression = argument.getArgumentExpression(); - if (jetExpression == null) { - throw new AssertionError("Argument with no expression encountered!"); - } - return Translation.translateAsExpression(jetExpression, context); - } } diff --git a/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java b/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java new file mode 100644 index 00000000000..57c3cc31ec6 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/initializer/AbstractInitializerTranslator.java @@ -0,0 +1,47 @@ +package org.jetbrains.k2js.translate.initializer; + +import com.google.dart.compiler.backend.js.ast.JsFunction; +import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; +import com.google.dart.compiler.backend.js.ast.JsScope; +import com.google.dart.compiler.backend.js.ast.JsStatement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.k2js.translate.AbstractTranslator; +import org.jetbrains.k2js.translate.Namer; +import org.jetbrains.k2js.translate.TranslationContext; + +import java.util.List; + +/** + * @author Talanov Pavel + */ +public abstract class AbstractInitializerTranslator extends AbstractTranslator { + + + @NotNull + protected final InitializerVisitor visitor; + @NotNull + protected final JsScope initializerMethodScope; + + protected AbstractInitializerTranslator(@NotNull JsScope initializerMethodScope, @NotNull TranslationContext context) { + super(context.newEnclosingScope(initializerMethodScope)); + this.visitor = new InitializerVisitor(); + this.initializerMethodScope = initializerMethodScope; + } + + abstract protected JsFunction generateInitializerFunction(); + + + @NotNull + public JsPropertyInitializer generateInitializeMethod() { + JsPropertyInitializer initializer = new JsPropertyInitializer(); + initializer.setLabelExpr(translationContext().program().getStringLiteral(Namer.INITIALIZE_METHOD_NAME)); + initializer.setValueExpr(generateInitializerFunction()); + return initializer; + } + + @NotNull + protected List translatePropertyAndAnonymousInitializers(@NotNull JetDeclaration declaration) { + return visitor.traverse(declaration, translationContext()); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java b/translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java new file mode 100644 index 00000000000..c9ead80fb0e --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/initializer/ClassInitializerTranslator.java @@ -0,0 +1,95 @@ +package org.jetbrains.k2js.translate.initializer; + +import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetDelegationSpecifier; +import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; +import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.k2js.translate.BindingUtils; +import org.jetbrains.k2js.translate.Namer; +import org.jetbrains.k2js.translate.TranslationContext; +import org.jetbrains.k2js.translate.TranslationUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Talanov Pavel + */ +public final class ClassInitializerTranslator extends AbstractInitializerTranslator { + + @NotNull + private final JetClass classDeclaration; + + public ClassInitializerTranslator(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { + super(new JsScope(context.getScopeForElement(classDeclaration), + "initializer " + classDeclaration.getName()), context); + this.classDeclaration = classDeclaration; + } + + @Override + @NotNull + protected JsFunction generateInitializerFunction() { + JsFunction result = JsFunction.getAnonymousFunctionWithScope(initializerMethodScope); + result.setParameters(translatePrimaryConstructorParameters()); + result.setBody(generateInitializerMethodBody()); + return result; + } + + @NotNull + private JsBlock generateInitializerMethodBody() { + + List initializerStatements = generateCallToSuperMethod(); + // initializerStatements.addAll(initializersForParameterProperties()); + initializerStatements.addAll(translatePropertyAndAnonymousInitializers(classDeclaration)); + return AstUtil.newBlock(initializerStatements); + } + + @NotNull + private List initializersForParameterProperties() { + return null; + } + + @NotNull + private List generateCallToSuperMethod() { + List result = new ArrayList(); + if (BindingUtils.hasAncestorClass(translationContext().bindingContext(), classDeclaration)) { + JsName superMethodName = initializerMethodScope.declareName(Namer.SUPER_METHOD_NAME); + List arguments = translateArguments(); + result.add(AstUtil.convertToStatement + (AstUtil.newInvocation(AstUtil.thisQualifiedReference(superMethodName), arguments))); + } + return result; + } + + @NotNull + private List translateArguments() { + JetDelegatorToSuperCall superCall = getSuperCall(); + return TranslationUtils.translateArgumentList(superCall.getValueArguments(), translationContext()); + } + + @NotNull + private JetDelegatorToSuperCall getSuperCall() { + JetDelegatorToSuperCall result = null; + for (JetDelegationSpecifier specifier : classDeclaration.getDelegationSpecifiers()) { + if (specifier instanceof JetDelegatorToSuperCall) { + result = (JetDelegatorToSuperCall) specifier; + } + } + assert result != null : "Class must call ancestor's constructor."; + return result; + } + + @NotNull + List translatePrimaryConstructorParameters() { + List result = new ArrayList(); + List parameters = classDeclaration.getPrimaryConstructorParameters(); + for (JetParameter parameter : parameters) { + JsName parameterName = initializerMethodScope.declareName(parameter.getName()); + result.add(new JsParameter(parameterName)); + } + return result; + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java new file mode 100644 index 00000000000..4c839c775eb --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/initializer/InitializerVisitor.java @@ -0,0 +1,91 @@ +package org.jetbrains.k2js.translate.initializer; + +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsStatement; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.k2js.translate.Translation; +import org.jetbrains.k2js.translate.TranslationContext; +import org.jetbrains.k2js.translate.TranslatorVisitor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Talanov Pavel + */ +public final class InitializerVisitor extends TranslatorVisitor> { + + + protected InitializerVisitor() { + } + + @Override + @NotNull + public List visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { + JetExpression initializer = expression.getInitializer(); + if (initializer == null) { + return new ArrayList(); + } + return Arrays.asList(translateInitializer(expression, context, initializer)); + } + + @NotNull + private JsStatement translateInitializer(@NotNull JetProperty property, @NotNull TranslationContext context, + @NotNull JetExpression initializer) { + JsExpression initExpression = Translation.translateAsExpression(initializer, context); + return assignmentToBackingField(property, initExpression, context); + } + + @NotNull + JsStatement assignmentToBackingField(@NotNull JetProperty property, @NotNull JsExpression initExpression, + @NotNull TranslationContext context) { + + return AstUtil.newAssignmentStatement(backingFieldReference(property, context), initExpression); + } + + @Override + @NotNull + public List visitAnonymousInitializer(@NotNull JetClassInitializer initializer, + @NotNull TranslationContext context) { + return Arrays.asList(Translation.translateAsStatement(initializer.getBody(), context)); + } + + @Override + @NotNull + // Not interested in other types of declarations, they do not contain initializers. + public List visitDeclaration(@NotNull JetDeclaration expression, @NotNull TranslationContext context) { + return new ArrayList(); + } + + @NotNull + public List traverseClass(@NotNull JetClass expression, @NotNull TranslationContext context) { + List initializerStatements = new ArrayList(); + for (JetDeclaration declaration : expression.getDeclarations()) { + initializerStatements.addAll(declaration.accept(this, context)); + } + return initializerStatements; + } + + @NotNull + public List traverseNamespace(@NotNull JetNamespace expression, @NotNull TranslationContext context) { + List initializerStatements = new ArrayList(); + for (JetDeclaration declaration : expression.getDeclarations()) { + initializerStatements.addAll(declaration.accept(this, context)); + } + return initializerStatements; + } + + @NotNull + public List traverse(@NotNull JetDeclaration declaration, @NotNull TranslationContext context) { + if (declaration instanceof JetNamespace) { + return traverseNamespace((JetNamespace) declaration, context); + } + if (declaration instanceof JetClass) { + return traverseClass((JetClass) declaration, context); + } + throw new AssertionError("Cannot traverse anything else."); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java b/translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java new file mode 100644 index 00000000000..6c2e7999808 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/initializer/NamespaceInitializerTranslator.java @@ -0,0 +1,33 @@ +package org.jetbrains.k2js.translate.initializer; + +import com.google.dart.compiler.backend.js.ast.JsFunction; +import com.google.dart.compiler.backend.js.ast.JsScope; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.k2js.translate.TranslationContext; + +/** + * @author Talanov Pavel + */ +public final class NamespaceInitializerTranslator extends AbstractInitializerTranslator { + + @NotNull + private final JetNamespace namespace; + + public NamespaceInitializerTranslator(@NotNull JetNamespace namespace, @NotNull TranslationContext context) { + super(new JsScope(context.getScopeForElement(namespace), + "initializer " + namespace.getName()), context); + this.namespace = namespace; + } + + @Override + @NotNull + protected JsFunction generateInitializerFunction() { + JsFunction result = JsFunction.getAnonymousFunctionWithScope(initializerMethodScope); + result.setBody(AstUtil.newBlock(translatePropertyAndAnonymousInitializers(namespace))); + return result; + } + + +} diff --git a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java index 8bb10e7019e..cde35b8cefa 100644 --- a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java +++ b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java @@ -30,6 +30,11 @@ public class BasicClassTest extends TranslationTest { testFooBoxIsTrue("constructorWithParameter.kt"); } + @Test + public void constructorWithPropertiesAsParameters() throws Exception { + testFooBoxIsTrue("constructorWithPropertiesAsParameters.kt"); + } + @Test public void incrementProperty() throws Exception { testFunctionOutput("incrementProperty.kt", "foo", "box", "OK"); diff --git a/translator/testFiles/class/cases/constructorWithPropertiesAsParameters.kt b/translator/testFiles/class/cases/constructorWithPropertiesAsParameters.kt new file mode 100644 index 00000000000..0a749b07e8c --- /dev/null +++ b/translator/testFiles/class/cases/constructorWithPropertiesAsParameters.kt @@ -0,0 +1,10 @@ +namespace foo + +class A(var b : Int, var a : String) { + +} + +fun box() : Boolean { + val c = A(1, "1") + return (c.b == 1 && c.a == "1") +} \ No newline at end of file