diff --git a/js/src/com/google/dart/compiler/util/AstUtil.java b/js/src/com/google/dart/compiler/util/AstUtil.java index b238bd4e9b1..1b583c11257 100644 --- a/js/src/com/google/dart/compiler/util/AstUtil.java +++ b/js/src/com/google/dart/compiler/util/AstUtil.java @@ -281,4 +281,43 @@ public class AstUtil { assert statement instanceof JsExprStmt : "Cannot extract exprssion form statement: " + statement; return (((JsExprStmt) statement).getExpression()); } + + public static JsBinaryOperation and(JsExpression op1, JsExpression op2) { + return new JsBinaryOperation(JsBinaryOperator.AND, op1, op2); + } + + public static JsBinaryOperation or(JsExpression op1, JsExpression op2) { + return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2); + } + + //TODO + public static void setQualifier(JsExpression selector, JsExpression receiver) { + if (selector instanceof JsInvocation) { + setQualifier(((JsInvocation) selector).getQualifier(), receiver); + return; + } + if (selector instanceof JsNameRef) { + JsNameRef nameRef = (JsNameRef) selector; + JsExpression qualifier = nameRef.getQualifier(); + if (qualifier == null) { + nameRef.setQualifier(receiver); + } else { + setQualifier(qualifier, receiver); + } + return; + } + throw new AssertionError("Set qualifier should be applied only to JsInvocation or JsNameRef instances"); + } + + public static JsBinaryOperation equals(JsExpression arg1, JsExpression arg2) { + return new JsBinaryOperation(JsBinaryOperator.REF_EQ, arg1, arg2); + } + + public static JsBinaryOperation notEqual(JsExpression arg1, JsExpression arg2) { + return new JsBinaryOperation(JsBinaryOperator.REF_NEQ, arg1, arg2); + } + + public static JsExpression equalsTrue(JsExpression expression, JsProgram program) { + return equals(expression, program.getTrueLiteral()); + } } diff --git a/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java b/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java index 4e16bf9dea6..6bfd26df152 100644 --- a/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java +++ b/translator/src/org/jetbrains/k2js/declarations/ExtractionVisitor.java @@ -71,6 +71,7 @@ public final class ExtractionVisitor extends DeclarationDescriptorVisitor> { + + @NotNull + protected final JsScope initializerMethodScope; + + @NotNull + protected final TranslationContext initializerMethodContext; + + protected AbstractInitializerVisitor(@NotNull TranslationContext enclosingContext, @NotNull JsScope newScope) { + this.initializerMethodContext = enclosingContext.newEnclosingScope(newScope); + this.initializerMethodScope = newScope; + } + + @NotNull + abstract protected JsFunction generate(); + + @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(); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java index e75af9b0327..c23af55bffb 100644 --- a/translator/src/org/jetbrains/k2js/translate/BindingUtils.java +++ b/translator/src/org/jetbrains/k2js/translate/BindingUtils.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import java.util.ArrayList; @@ -77,10 +78,23 @@ public final class BindingUtils { return result; } + @NotNull + static public JetClass getClassForDescriptor(@NotNull BindingContext context, + @NotNull ClassDescriptor descriptor) { + PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); + assert result instanceof JetClass : "ClassDescriptor should have declaration of type JetClass"; + return (JetClass) result; + } + @NotNull static public List getSuperclassDescriptors(@NotNull BindingContext context, @NotNull JetClass classDeclaration) { ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration); + return getSuperclassDescriptors(classDescriptor); + } + + @NotNull + static public List getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) { Collection superclassTypes = classDescriptor.getTypeConstructor().getSupertypes(); List superClassDescriptors = new ArrayList(); for (JetType type : superclassTypes) { @@ -139,7 +153,7 @@ public final class BindingUtils { //TODO move unrelated utils to other class @Nullable - public static ClassDescriptor findAncestorClass(@NotNull List superclassDescriptors) { + static public ClassDescriptor findAncestorClass(@NotNull List superclassDescriptors) { for (ClassDescriptor descriptor : superclassDescriptors) { if (descriptor.getKind() == ClassKind.CLASS) { return descriptor; @@ -147,4 +161,14 @@ public final class BindingUtils { } return null; } + + static public boolean belongsToNamespace(@NotNull BindingContext context, @NotNull JetProperty property) { + return getPropertyDescriptor(context, property).getContainingDeclaration() instanceof NamespaceDescriptor; + } + + @Nullable + static public ResolvedCall getResolvedCall(@NotNull BindingContext context, + @NotNull JetExpression expression) { + return (context.get(BindingContext.RESOLVED_CALL, expression)); + } } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java new file mode 100644 index 00000000000..948669f08ba --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/ClassDeclarationTranslator.java @@ -0,0 +1,112 @@ +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.annotations.Nullable; +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.utils.ClassSorter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Talanov Pavel + */ +//TODO: implement +public final class ClassDeclarationTranslator extends AbstractTranslator { + + @NotNull + private final JetNamespace namespace; + @NotNull + private final Map localToGlobalClassName; + @NotNull + private final JsScope dummyFunctionScope; + @Nullable + private JsName declarationsObject = null; + @Nullable + private JsStatement declarationsStatement = null; + + public ClassDeclarationTranslator(@NotNull TranslationContext context, @NotNull JetNamespace namespace) { + super(context); + this.namespace = namespace; + this.localToGlobalClassName = new HashMap(); + this.dummyFunctionScope = new JsScope(translationContext().enclosingScope(), "class declaration function"); + } + + public void generateDeclarations() { + declarationsObject = translationContext().enclosingScope().declareName(Namer.nameForClassesVariable()); + assert declarationsObject != null; + declarationsStatement = + AstUtil.newAssignmentStatement(declarationsObject.makeRef(), generateDummyFunctionInvocation()); + } + + @NotNull + public JsName getDeclarationsObjectName() { + assert declarationsObject != null : "Should run generateDeclarations first"; + return declarationsObject; + } + + @NotNull + public JsStatement getDeclarationsStatement() { + assert declarationsStatement != null : "Should run generateDeclarations first"; + return declarationsStatement; + } + + @NotNull + private JsInvocation generateDummyFunctionInvocation() { + JsFunction dummyFunction = JsFunction.getAnonymousFunctionWithScope(dummyFunctionScope); + List classDeclarations = generateClassDeclarationStatements(); + classDeclarations.add(new JsReturn(generateReturnedObjectLiteral())); + dummyFunction.setBody(AstUtil.newBlock(classDeclarations)); + return AstUtil.newInvocation(dummyFunction); + } + + @NotNull + private JsObjectLiteral generateReturnedObjectLiteral() { + JsObjectLiteral returnedValueLiteral = new JsObjectLiteral(); + for (JsName localName : localToGlobalClassName.keySet()) { + returnedValueLiteral.getPropertyInitializers().add(classEntry(localName)); + } + return returnedValueLiteral; + } + + @NotNull + private JsPropertyInitializer classEntry(@NotNull JsName localName) { + return new JsPropertyInitializer(localToGlobalClassName.get(localName).makeRef(), localName.makeRef()); + } + + @NotNull + private List generateClassDeclarationStatements() { + List classDeclarations = new ArrayList(); + for (JetClass jetClass : getClassDeclarations()) { + classDeclarations.add(generateDeclaration(jetClass)); + } + return classDeclarations; + } + + @NotNull + private List getClassDeclarations() { + List classes = new ArrayList(); + for (JetDeclaration declaration : namespace.getDeclarations()) { + if (declaration instanceof JetClass) { + classes.add((JetClass) declaration); + } + } + return ClassSorter.sortUsingInheritanceOrder(classes, translationContext().bindingContext()); + } + + @NotNull + private JsStatement generateDeclaration(@NotNull JetClass declaration) { + JsName globalClassName = translationContext().getNameForElement(declaration); + JsName localClassName = dummyFunctionScope.declareName(globalClassName.getIdent()); + localToGlobalClassName.put(localClassName, globalClassName); + JsInvocation classDeclarationExpression = + Translation.classTranslator(translationContext()).translateClass(declaration); + return AstUtil.newVar(localClassName, classDeclarationExpression); + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java similarity index 54% rename from translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java rename to translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java index 56bb69f26ab..95502588c0a 100644 --- a/translator/src/org/jetbrains/k2js/translate/InitializerVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassInitializerVisitor.java @@ -6,34 +6,25 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** * @author Talanov Pavel - *

- * This visitor collects all initializers from a given class into JsFunction object. - * Note: we do use visitor pattern to preserve the order in which initializers are executed. */ -public class InitializerVisitor extends TranslatorVisitor> { +public final class ClassInitializerVisitor extends AbstractInitializerVisitor { - @NotNull - private final JsScope initializerMethodScope; @NotNull private final JetClass classDeclaration; - @NotNull - private final TranslationContext initializerMethodContext; - public InitializerVisitor(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { - this.initializerMethodScope = new JsScope(context.getScopeForElement(classDeclaration), - "initializer " + classDeclaration.getName()); + public ClassInitializerVisitor(@NotNull JetClass classDeclaration, @NotNull TranslationContext context) { + super(context, new JsScope(context.getScopeForElement(classDeclaration), + "initializer " + classDeclaration.getName())); this.classDeclaration = classDeclaration; - this.initializerMethodContext = context.newEnclosingScope(initializerMethodScope); - } + @Override @NotNull - public JsFunction generateInitializeMethod() { + public JsFunction generate() { JsFunction result = JsFunction.getAnonymousFunctionWithScope(initializerMethodScope); result.setParameters(translatePrimaryConstructorParameters(classDeclaration)); result.setBody(generateInitializerMethodBody(classDeclaration, initializerMethodContext)); @@ -81,7 +72,6 @@ public class InitializerVisitor extends TranslatorVisitor> { return result; } - @Override @NotNull public List visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { @@ -102,52 +92,4 @@ public class InitializerVisitor extends TranslatorVisitor> { } return result; } - - @Override - @NotNull - public List visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { - JetExpression initializer = expression.getInitializer(); - declareBackingFieldName(expression); - if (initializer == null) { - return new ArrayList(); - } - return Arrays.asList(translateInitializer(expression, context, initializer)); - } - - private void declareBackingFieldName(@NotNull JetProperty property) { - initializerMethodScope.declareName(Namer.getKotlinBackingFieldName(property.getName())); - } - - @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) { - String propertyName = property.getName(); - assert propertyName != null : "Named property expected."; - JsName backingFieldName = getBackingFieldName(propertyName, context); - JsNameRef backingFieldRef = backingFieldName.makeRef(); - backingFieldRef.setQualifier(new JsThisRef()); - return AstUtil.newAssignmentStatement(backingFieldRef, 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(); - } - } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java index 44e6e51ec58..22c6e54cbe2 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ClassTranslator.java @@ -1,6 +1,9 @@ package org.jetbrains.k2js.translate; -import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.backend.js.ast.JsInvocation; +import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.backend.js.ast.JsObjectLiteral; +import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +22,7 @@ import java.util.List; public final class ClassTranslator extends AbstractTranslator { @NotNull - private final ClassBodyVisitor classBodyVisitor = new ClassBodyVisitor(); + private final DeclarationBodyVisitor declarationBodyVisitor = new DeclarationBodyVisitor(); @NotNull public static ClassTranslator newInstance(@NotNull TranslationContext context) { @@ -31,11 +34,11 @@ public final class ClassTranslator extends AbstractTranslator { } @NotNull - public JsStatement translateClass(@NotNull JetClass jetClassDeclaration) { + public JsInvocation translateClass(@NotNull JetClass jetClassDeclaration) { JsInvocation jsClassDeclaration = classCreateMethodInvocation(jetClassDeclaration); addSuperclassReferences(jetClassDeclaration, jsClassDeclaration); addClassOwnDeclarations(jetClassDeclaration, jsClassDeclaration); - return classDeclarationStatement(jetClassDeclaration, jsClassDeclaration); + return jsClassDeclaration; } @NotNull @@ -47,19 +50,6 @@ public final class ClassTranslator extends AbstractTranslator { } } - @NotNull - private JsStatement classDeclarationStatement(@NotNull JetClass classDeclaration, - @NotNull JsInvocation jsClassDeclaration) { - return AstUtil.newAssignmentStatement - (namespaceQualifiedClassNameReference(classDeclaration), jsClassDeclaration); - } - - @NotNull - private JsNameRef namespaceQualifiedClassNameReference(@NotNull JetClass classDeclaration) { - return translationContext().getNamespaceQualifiedReference - (translationContext().getNameForElement(classDeclaration)); - } - private void addClassOwnDeclarations(@NotNull JetClass classDeclaration, @NotNull JsInvocation jsClassDeclaration) { JsObjectLiteral jsClassDescription = translateClassDeclarations(classDeclaration); @@ -119,27 +109,10 @@ public final class ClassTranslator extends AbstractTranslator { private JsObjectLiteral translateClassDeclarations(@NotNull JetClass classDeclaration) { List propertyList = new ArrayList(); if (!classDeclaration.isTrait()) { - propertyList.add(generateInitializeMethod(classDeclaration)); + propertyList.add(InitializerGenerator.generateInitializeMethod(classDeclaration, translationContext())); } - propertyList.addAll(classDeclaration.accept(classBodyVisitor, + propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, translationContext().newClass(classDeclaration))); return new JsObjectLiteral(propertyList); } - - // TODO: names are inconsistent - @NotNull - private JsPropertyInitializer generateInitializeMethod(@NotNull JetClass classDeclaration) { - JsPropertyInitializer initializer = new JsPropertyInitializer(); - initializer.setLabelExpr(program().getStringLiteral(Namer.INITIALIZE_METHOD_NAME)); - initializer.setValueExpr(generateInitializeMethodBody(classDeclaration)); - return initializer; - } - - @NotNull - private JsFunction generateInitializeMethodBody(@NotNull JetClass classDeclaration) { - InitializerVisitor initializerVisitor = new InitializerVisitor(classDeclaration, - translationContext().newClass(classDeclaration)); - return initializerVisitor.generateInitializeMethod(); - } - } diff --git a/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java b/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java similarity index 85% rename from translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java rename to translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java index 57798ae81e9..082e6628d2b 100644 --- a/translator/src/org/jetbrains/k2js/translate/ClassBodyVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/DeclarationBodyVisitor.java @@ -9,16 +9,28 @@ import org.jetbrains.jet.lang.psi.*; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** * @author Talanov Pavel */ -public final class ClassBodyVisitor extends TranslatorVisitor> { +public final class DeclarationBodyVisitor extends TranslatorVisitor> { + - @Override @NotNull - public List visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { + public List traverseClass(@NotNull JetClass expression, + @NotNull TranslationContext context) { + List properties = new ArrayList(); + for (JetDeclaration declaration : expression.getDeclarations()) { + properties.addAll(declaration.accept(this, context)); + } + return properties; + } + + @NotNull + public List traverseNamespace(@NotNull JetNamespace expression, + @NotNull TranslationContext context) { List properties = new ArrayList(); for (JetDeclaration declaration : expression.getDeclarations()) { properties.addAll(declaration.accept(this, context)); @@ -28,11 +40,15 @@ public final class ClassBodyVisitor extends TranslatorVisitor visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { + //TODO: we are interested only in class own declarations + return Collections.emptyList(); + } + + @Override + @NotNull public List visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) { - List properties = new ArrayList(); - properties.add(Translation.functionTranslator(context).translateAsMethod(expression)); - return properties; + return Arrays.asList(Translation.functionTranslator(context).translateAsMethod(expression)); } @Override @@ -78,9 +94,7 @@ public final class ClassBodyVisitor extends TranslatorVisitor(), AstUtil.convertToBlock(returnExpression)); } @@ -108,13 +122,9 @@ public final class ClassBodyVisitor extends TranslatorVisitor visitAnonymousInitializer(@NotNull JetClassInitializer expression, @NotNull TranslationContext context) { // parsed it in initializer visitor => no additional actions are needed - return new ArrayList(); + return Collections.emptyList(); } } diff --git a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java index b05204f6ede..32530e12aae 100644 --- a/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/ExpressionVisitor.java @@ -108,8 +108,9 @@ public final class ExpressionVisitor extends TranslatorVisitor { private boolean isConstructorInvocation(@NotNull JetCallExpression expression, @NotNull TranslationContext context) { - ResolvedCall resolvedCall = - (context.bindingContext().get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression())); + JetExpression calleeExpression = expression.getCalleeExpression(); + assert calleeExpression != null : "JetCallExpression should have not null callee"; + ResolvedCall resolvedCall = BindingUtils.getResolvedCall(context.bindingContext(), calleeExpression); if (resolvedCall == null) { return false; } @@ -249,6 +250,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { return null; } + //TODO: refactor and possibly move somewhere @Override @NotNull public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, @@ -342,10 +344,9 @@ public final class ExpressionVisitor extends TranslatorVisitor { @NotNull TranslationContext context) { JsExpression receiver = translateReceiver(expression, context); JsNullLiteral nullLiteral = context.program().getNullLiteral(); - JsBinaryOperation nullCheck = new JsBinaryOperation - (JsBinaryOperator.NEQ, receiver, nullLiteral); JsExpression thenExpression = translateQualifiedExpression(expression, context); - return new JsConditional(nullCheck, thenExpression, nullLiteral); + return new JsConditional(TranslationUtils.notNullCheck(context, receiver), + thenExpression, nullLiteral); } @Override diff --git a/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java b/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java index 9d39c124d24..4765575d6bf 100644 --- a/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/FunctionTranslator.java @@ -22,14 +22,6 @@ public final class FunctionTranslator extends AbstractTranslator { super(context); } - @NotNull - public JsStatement translateAsFunctionDeclaration(@NotNull JetNamedFunction expression) { - JsName functionName = translationContext().getNameForElement(expression); - JsFunction function = generateFunctionObject(expression); - return AstUtil.newAssignmentStatement - (translationContext().getNamespaceQualifiedReference(functionName), function); - } - @NotNull JsPropertyInitializer translateAsMethod(@NotNull JetNamedFunction expression) { JsName functionName = translationContext().getNameForElement(expression); diff --git a/translator/src/org/jetbrains/k2js/translate/GenerationState.java b/translator/src/org/jetbrains/k2js/translate/GenerationState.java index 453369144ec..2cf358d7698 100644 --- a/translator/src/org/jetbrains/k2js/translate/GenerationState.java +++ b/translator/src/org/jetbrains/k2js/translate/GenerationState.java @@ -18,7 +18,6 @@ public final class GenerationState { public GenerationState() { } - //TODO method too long @NotNull public JsProgram compileCorrectNamespaces(@NotNull BindingContext bindingContext, @NotNull List namespaces) { //TODO hardcoded @@ -26,8 +25,7 @@ public final class GenerationState { JetNamespace namespace = namespaces.get(0); NamespaceDescriptor descriptor = BindingUtils.getNamespaceDescriptor(bindingContext, namespace); Declarations declarations = Declarations.extractDeclarations(descriptor, result.getRootScope()); - Translation.namespaceTranslator(TranslationContext.rootContext(result, bindingContext, declarations)) - .generateAst(namespace); + Translation.generateAst(result, bindingContext, declarations, namespace); return result; } diff --git a/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java b/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java new file mode 100644 index 00000000000..2126333201f --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/InitializerGenerator.java @@ -0,0 +1,54 @@ +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; + } + + @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/Namer.java b/translator/src/org/jetbrains/k2js/translate/Namer.java index 533bfa6a411..c912338f3c0 100644 --- a/translator/src/org/jetbrains/k2js/translate/Namer.java +++ b/translator/src/org/jetbrains/k2js/translate/Namer.java @@ -71,9 +71,21 @@ public final class Namer { return AstUtil.newQualifiedNameRef("Trait.create"); } + public static JsNameRef namespaceCreationMethodReference() { + return AstUtil.newQualifiedNameRef("Namespace.create"); + } + public static JsNameRef isOperationReference() { return AstUtil.newQualifiedNameRef("isType"); } + public static JsNameRef initializeMethodReference() { + return AstUtil.newQualifiedNameRef("initialize"); + } + + public static String nameForClassesVariable() { + return "classes"; + } + } diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationTranslator.java b/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationTranslator.java deleted file mode 100644 index 4ef42250b6e..00000000000 --- a/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationTranslator.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.k2js.translate; - -import com.google.dart.compiler.backend.js.ast.JsStatement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetDeclaration; - -/** - * @author Talanov Pavel - */ -public final class NamespaceDeclarationTranslator extends AbstractTranslator { - - private NamespaceDeclarationVisitor visitor = new NamespaceDeclarationVisitor(); - - @NotNull - public static NamespaceDeclarationTranslator newInstance(@NotNull TranslationContext context) { - return new NamespaceDeclarationTranslator(context); - } - - private NamespaceDeclarationTranslator(TranslationContext context) { - super(context); - } - - @NotNull - JsStatement translateDeclaration(JetDeclaration declaration) { - return declaration.accept(visitor, translationContext()); - } - - -} diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationVisitor.java b/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationVisitor.java deleted file mode 100644 index be783500ff6..00000000000 --- a/translator/src/org/jetbrains/k2js/translate/NamespaceDeclarationVisitor.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.jetbrains.k2js.translate; - -import com.google.dart.compiler.backend.js.ast.JsExpression; -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.JsStatement; -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.JetNamedFunction; -import org.jetbrains.jet.lang.psi.JetProperty; - -/** - * @author Talanov Pavel - */ -//TODO: rework the class -public class NamespaceDeclarationVisitor extends TranslatorVisitor { - - @NotNull - @Override - //TODO method too long - public JsStatement visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) { - JsName propertyName = context.declareLocalName(getPropertyName(expression)); - JsNameRef jsPropertyNameReference = context.getNamespaceQualifiedReference(propertyName); - JsExpression jsInitExpression = translateInitializerForProperty(expression, context); - JsExpression result; - if (jsInitExpression != null) { - result = AstUtil.newAssignment(jsPropertyNameReference, jsInitExpression); - } else { - result = jsPropertyNameReference; - } - return AstUtil.convertToStatement(result); - } - - @NotNull - @Override - public JsStatement visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) { - return Translation.classTranslator(context).translateClass(expression); - } - - @NotNull - @Override - public JsStatement visitNamedFunction(@NotNull JetNamedFunction expression, @NotNull TranslationContext context) { - return AstUtil.convertToStatement(Translation.functionTranslator(context).translateAsFunctionDeclaration(expression)); - } - -} diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceInitializerVisitor.java b/translator/src/org/jetbrains/k2js/translate/NamespaceInitializerVisitor.java new file mode 100644 index 00000000000..4915eb42e78 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/NamespaceInitializerVisitor.java @@ -0,0 +1,46 @@ +package org.jetbrains.k2js.translate; + +import com.google.dart.compiler.backend.js.ast.JsFunction; +import com.google.dart.compiler.backend.js.ast.JsScope; +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.JetDeclaration; +import org.jetbrains.jet.lang.psi.JetNamespace; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Talanov Pavel + */ +public final class NamespaceInitializerVisitor extends AbstractInitializerVisitor { + + @NotNull + private final JetNamespace namespace; + + public NamespaceInitializerVisitor(@NotNull JetNamespace namespace, @NotNull TranslationContext context) { + super(context, new JsScope(context.getScopeForElement(namespace), + "initializer " + namespace.getName())); + this.namespace = namespace; + } + + @Override + @NotNull + public JsFunction generate() { + JsFunction result = JsFunction.getAnonymousFunctionWithScope(initializerMethodScope); + result.setBody(AstUtil.newBlock(namespace.accept(this, initializerMethodContext))); + return result; + } + + @Override + @NotNull + public List visitNamespace(@NotNull JetNamespace expression, @NotNull TranslationContext context) { + List initializerStatements = new ArrayList(); + for (JetDeclaration declaration : expression.getDeclarations()) { + initializerStatements.addAll(declaration.accept(this, context)); + } + return initializerStatements; + } + +} diff --git a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java index 511e3392928..08836714537 100644 --- a/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/NamespaceTranslator.java @@ -3,7 +3,6 @@ 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.JetDeclaration; import org.jetbrains.jet.lang.psi.JetNamespace; import java.util.ArrayList; @@ -15,58 +14,73 @@ import java.util.List; public final class NamespaceTranslator extends AbstractTranslator { @NotNull - public static NamespaceTranslator newInstance(@NotNull TranslationContext context) { - return new NamespaceTranslator(context); + private final JetNamespace namespace; + @NotNull + private final JsName namespaceName; + @NotNull + private final ClassDeclarationTranslator classDeclarationTranslator; + + @NotNull + public static JsStatement translate(@NotNull TranslationContext context, + @NotNull JetNamespace namespace) { + return (new NamespaceTranslator(context, namespace)).translateNamespace(); } - private NamespaceTranslator(@NotNull TranslationContext context) { + private NamespaceTranslator(@NotNull TranslationContext context, @NotNull JetNamespace namespace) { super(context); - } - - public JsProgram generateAst(@NotNull JetNamespace namespace) { - translate(namespace); - return program(); - } - - //TODO logic unclear - @NotNull - public JsBlock translate(@NotNull JetNamespace namespace) { - // TODO support multiple namespaces - JsBlock block = program().getFragmentBlock(0); - JsName namespaceName = translationContext().enclosingScope().declareName(Namer.getNameForNamespace(namespace.getName())); - block.addStatement(namespaceInitStatement(namespaceName)); - TranslationContext newContext = translationContext().newNamespace(namespace); - JsFunction dummyFunction = JsFunction.getAnonymousFunctionWithScope - (translationContext().getScopeForElement(namespace)); - JsBlock namespaceDeclarations = translateDeclarations(namespace, newContext); - JsInvocation namespaceExpression = newNamespace(namespaceName, namespaceDeclarations, dummyFunction); - block.addStatement(AstUtil.convertToStatement(namespaceExpression)); - return block; + this.namespace = namespace; + this.namespaceName = context.getNameForElement(namespace); + this.classDeclarationTranslator = new ClassDeclarationTranslator(context, namespace); } @NotNull - private JsBlock translateDeclarations(@NotNull JetNamespace namespace, @NotNull TranslationContext newContext) { - NamespaceDeclarationTranslator namespaceDeclarationTranslator = Translation.declarationTranslator(newContext); - JsBlock namespaceDeclarations = new JsBlock(); - for (JetDeclaration declaration : namespace.getDeclarations()) { - namespaceDeclarations.addStatement(namespaceDeclarationTranslator.translateDeclaration(declaration)); - } - return namespaceDeclarations; + public JsStatement translateNamespace() { + classDeclarationTranslator.generateDeclarations(); + return AstUtil.newBlock(classDeclarationsStatement(), + namespaceOwnDeclarationStatement(), + namespaceInitializeStatement()); + } + + private JsStatement classDeclarationsStatement() { + return classDeclarationTranslator.getDeclarationsStatement(); } @NotNull - private JsStatement namespaceInitStatement(@NotNull JsName namespaceName) { - return AstUtil.newAssignmentStatement(namespaceName.makeRef(), new JsObjectLiteral()); + private JsStatement namespaceInitializeStatement() { + JsNameRef initializeMethodReference = Namer.initializeMethodReference(); + AstUtil.setQualifier(initializeMethodReference, namespaceName.makeRef()); + return AstUtil.newInvocation(initializeMethodReference).makeStmt(); } @NotNull - private JsInvocation newNamespace(@NotNull JsName name, @NotNull JsBlock namespaceDeclarations, - @NotNull JsFunction dummyFunction) { - List params = new ArrayList(); - params.add(new JsParameter(name)); - dummyFunction.setParameters(params); - JsExpression invocationParam = name.makeRef(); - dummyFunction.setBody(namespaceDeclarations); - return AstUtil.newInvocation(dummyFunction, invocationParam); + private JsInvocation namespaceCreateMethodInvocation() { + return AstUtil.newInvocation(Namer.namespaceCreationMethodReference()); + } + + @NotNull + private JsStatement namespaceOwnDeclarationStatement() { + JsInvocation namespaceDeclaration = namespaceCreateMethodInvocation(); + addMemberDeclarations(namespaceDeclaration); + addClassesDeclarations(namespaceDeclaration); + return AstUtil.newAssignmentStatement + (translationContext().getNameForElement(namespace).makeRef(), namespaceDeclaration); + } + + private void addClassesDeclarations(@NotNull JsInvocation namespaceDeclaration) { + namespaceDeclaration.getArguments().add(classDeclarationTranslator.getDeclarationsObjectName().makeRef()); + } + + private void addMemberDeclarations(@NotNull JsInvocation jsNamespace) { + JsObjectLiteral jsClassDescription = translateNamespaceMemberDeclarations(); + jsNamespace.getArguments().add(jsClassDescription); + } + + @NotNull + private JsObjectLiteral translateNamespaceMemberDeclarations() { + List propertyList = new ArrayList(); + propertyList.add(InitializerGenerator.generateInitializeMethod(namespace, translationContext())); + propertyList.addAll(new DeclarationBodyVisitor().traverseNamespace(namespace, + translationContext().newNamespace(namespace))); + return new JsObjectLiteral(propertyList); } } diff --git a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java index b725ffbc856..8a16ccd3af6 100644 --- a/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/OperationTranslator.java @@ -1,9 +1,11 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.util.AstUtil; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lexer.JetToken; @@ -70,7 +72,7 @@ public final class OperationTranslator extends AbstractTranslator { } JetExpression leftExpression = expression.getLeft(); JsInvocation setterCall = Translation.propertyAccessTranslator(translationContext()). - resolveAsPropertySetterCall(leftExpression); + translateAsPropertySetterCall(leftExpression); if (setterCall == null) { return null; } @@ -81,8 +83,14 @@ public final class OperationTranslator extends AbstractTranslator { @NotNull private JsExpression translateAsBinaryOperation(@NotNull JetBinaryExpression expression) { + JsExpression left = Translation.translateAsExpression(expression.getLeft(), translationContext()); JsExpression right = translateRightExpression(expression); + + JsNameRef operationReference = getOverloadedOperationReference(expression); + if (operationReference != null) { + return overloadedMethodInvocation(left, right, operationReference); + } JetToken token = getOperationToken(expression); if (OperatorTable.hasCorrespondingBinaryOperator(token)) { return new JsBinaryOperation(OperatorTable.getBinaryOperator(token), left, right); @@ -95,6 +103,24 @@ public final class OperationTranslator extends AbstractTranslator { throw new AssertionError("Unsupported token encountered: " + token.toString()); } + private JsExpression overloadedMethodInvocation(JsExpression left, JsExpression right, JsNameRef operationReference) { + operationReference.setQualifier(left); + return AstUtil.newInvocation(operationReference, right); + } + + @Nullable + private JsNameRef getOverloadedOperationReference(@NotNull JetBinaryExpression expression) { + DeclarationDescriptor operationDescriptor = BindingUtils.getDescriptorForReferenceExpression + (translationContext().bindingContext(), expression.getOperationReference()); + if (operationDescriptor == null) { + return null; + } + if (!translationContext().isDeclared(operationDescriptor)) { + return null; + } + return translationContext().getNameForDescriptor(operationDescriptor).makeRef(); + } + @NotNull private JsExpression translateRightExpression(@NotNull JetBinaryExpression expression) { JetExpression rightExpression = expression.getRight(); diff --git a/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java b/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java index 2de2defcff8..e7eac5f991e 100644 --- a/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PatternTranslator.java @@ -1,6 +1,9 @@ package org.jetbrains.k2js.translate; -import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsInvocation; +import com.google.dart.compiler.backend.js.ast.JsName; +import com.google.dart.compiler.backend.js.ast.JsNameRef; import com.google.dart.compiler.util.AstUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -52,14 +55,36 @@ public final class PatternTranslator extends AbstractTranslator { @NotNull private JsExpression translateTypePattern(@NotNull JsExpression expressionToMatch, @NotNull JetTypePattern pattern) { - return AstUtil.newInvocation(Namer.isOperationReference(), expressionToMatch, getClassReference(pattern)); + + JsInvocation isCheck = AstUtil.newInvocation(Namer.isOperationReference(), + expressionToMatch, getClassReference(pattern)); + if (isNullable(pattern)) { + return addNullCheck(expressionToMatch, isCheck); + } + return isCheck; + } + + @NotNull + private JsExpression addNullCheck(@NotNull JsExpression expressionToMatch, @NotNull JsInvocation isCheck) { + return AstUtil.or(TranslationUtils.isNullCheck(translationContext(), expressionToMatch), isCheck); + } + + private boolean isNullable(JetTypePattern pattern) { + return BindingUtils.getTypeByReference(translationContext().bindingContext(), + getTypeReference(pattern)).isNullable(); } @NotNull private JsExpression getClassReference(@NotNull JetTypePattern pattern) { + JetTypeReference typeReference = getTypeReference(pattern); + return getClassNameReferenceForTypeReference(typeReference); + } + + @NotNull + private JetTypeReference getTypeReference(@NotNull JetTypePattern pattern) { JetTypeReference typeReference = pattern.getTypeReference(); assert typeReference != null : "Type pattern should contain a type reference"; - return getClassNameReferenceForTypeReference(typeReference); + return typeReference; } @NotNull @@ -77,7 +102,6 @@ public final class PatternTranslator extends AbstractTranslator { assert patternExpression != null : "Expression patter should have an expression."; JsExpression expressionToMatchAgainst = Translation.translateAsExpression(patternExpression, translationContext()); - //TODO: should call equals method here - return new JsBinaryOperation(JsBinaryOperator.REF_EQ, expressionToMatch, expressionToMatchAgainst); + return AstUtil.equals(expressionToMatch, expressionToMatchAgainst); } } diff --git a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java index 048b2a11fc1..2ef432566fa 100644 --- a/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/PropertyAccessTranslator.java @@ -15,7 +15,6 @@ import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; /** @@ -50,7 +49,9 @@ public final class PropertyAccessTranslator extends AbstractTranslator { if (getterName == null) { return null; } - return AstUtil.newInvocation(AstUtil.thisQualifiedReference(getterName)); + JsNameRef getterReference = + TranslationUtils.getReference(translationContext(), expression, getterName); + return AstUtil.newInvocation(getterReference); } @NotNull @@ -59,12 +60,12 @@ public final class PropertyAccessTranslator extends AbstractTranslator { JsExpression qualifier = Translation.translateAsExpression (qualifiedExpression.getReceiverExpression(), translationContext()); JsNameRef result = accessorName.makeRef(); - result.setQualifier(qualifier); + AstUtil.setQualifier(result, qualifier); return AstUtil.newInvocation(result); } @Nullable - public JsInvocation resolveAsPropertySetterCall(@NotNull JetExpression expression) { + public JsInvocation translateAsPropertySetterCall(@NotNull JetExpression expression) { if (expression instanceof JetDotQualifiedExpression) { return resolveAsPropertySet((JetDotQualifiedExpression) expression); } @@ -91,7 +92,8 @@ public final class PropertyAccessTranslator extends AbstractTranslator { if (setterName == null) { return null; } - return AstUtil.newInvocation(AstUtil.thisQualifiedReference(setterName)); + JsNameRef setterReference = Translation.generateCorrectReference(translationContext(), expression, setterName); + return AstUtil.newInvocation(setterReference); } @Nullable @@ -123,7 +125,7 @@ public final class PropertyAccessTranslator extends AbstractTranslator { @Nullable private PropertyDescriptor getPropertyDescriptor(@NotNull JetExpression expression) { ResolvedCall resolvedCall = - translationContext().bindingContext().get(BindingContext.RESOLVED_CALL, expression); + BindingUtils.getResolvedCall(translationContext().bindingContext(), expression); if (resolvedCall != null) { DeclarationDescriptor descriptor = resolvedCall.getCandidateDescriptor(); if (descriptor instanceof PropertyDescriptor) { diff --git a/translator/src/org/jetbrains/k2js/translate/ReferenceProvider.java b/translator/src/org/jetbrains/k2js/translate/ReferenceProvider.java new file mode 100644 index 00000000000..3d53b06d604 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/ReferenceProvider.java @@ -0,0 +1,52 @@ +package org.jetbrains.k2js.translate; + +import com.google.dart.compiler.backend.js.ast.JsName; +import com.google.dart.compiler.backend.js.ast.JsNameRef; +import com.google.dart.compiler.util.AstUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; +import org.jetbrains.jet.lexer.JetTokens; + +/** + * @author Talanov Pavel + */ +public final class ReferenceProvider { + + @NotNull + private final TranslationContext context; + @NotNull + private final JsName referencedName; + private boolean requiresThisQualifier; + private boolean requiresNamespaceQualifier; + + + public ReferenceProvider(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression, + @NotNull JsName referencedName) { + this.context = context; + this.referencedName = referencedName; + this.requiresThisQualifier = requiresThisQualifier(expression); + this.requiresNamespaceQualifier = requiresNamespaceQualifier(); + } + + @NotNull + public JsNameRef generateCorrectReference() { + if (requiresNamespaceQualifier) { + return context.getNamespaceQualifiedReference(referencedName); + } else if (requiresThisQualifier) { + return AstUtil.thisQualifiedReference(referencedName); + } + return referencedName.makeRef(); + } + + private boolean requiresNamespaceQualifier() { + return context.namespaceScope().ownsName(referencedName); + } + + private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression) { + JsName name = context.enclosingScope().findExistingName(referencedName.getIdent()); + boolean isClassMember = context.classScope().ownsName(name); + boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; + return isClassMember || isBackingFieldAccess; + } +} diff --git a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java index 12cda448210..eba33d226df 100644 --- a/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/ReferenceTranslator.java @@ -1,11 +1,12 @@ package org.jetbrains.k2js.translate; -import com.google.dart.compiler.backend.js.ast.*; +import com.google.dart.compiler.backend.js.ast.JsExpression; +import com.google.dart.compiler.backend.js.ast.JsInvocation; +import com.google.dart.compiler.backend.js.ast.JsName; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; -import org.jetbrains.jet.lexer.JetTokens; /** * @author Talanov Pavel @@ -23,10 +24,11 @@ public class ReferenceTranslator extends AbstractTranslator { @NotNull JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression) { - //TODO: this is only a hack for now - // Problem is that namespace properties do not generate getters and setter actually so they must be referenced - // by name JsExpression result; + result = resolveAsPropertyAccess(expression); + if (result != null) { + return result; + } result = resolveAsGlobalReference(expression); if (result != null) { return result; @@ -35,15 +37,15 @@ public class ReferenceTranslator extends AbstractTranslator { if (result != null) { return result; } - JsInvocation getterCall = - Translation.propertyAccessTranslator(translationContext()).resolveAsPropertyGet(expression); - if (getterCall != null) { - return getterCall; - } throw new AssertionError("Undefined name in this scope: " + expression.getReferencedName()); } + @Nullable + private JsInvocation resolveAsPropertyAccess(@NotNull JetSimpleNameExpression expression) { + return Translation.propertyAccessTranslator(translationContext()).resolveAsPropertyGet(expression); + } + @Nullable private JsExpression resolveAsGlobalReference(@NotNull JetSimpleNameExpression expression) { DeclarationDescriptor referencedDescriptor = @@ -55,48 +57,19 @@ public class ReferenceTranslator extends AbstractTranslator { return null; } JsName referencedName = translationContext().getNameForDescriptor(referencedDescriptor); - return generateCorrectReference(expression, referencedName); + return TranslationUtils.getReference(translationContext(), expression, referencedName); } @Nullable private JsExpression resolveAsLocalReference(@NotNull JetSimpleNameExpression expression) { - JsName localReferencedName = getLocalReferencedName(expression); + String name = expression.getReferencedName(); + assert name != null : "SimpleNameExpression should reference a name"; + JsName localReferencedName = TranslationUtils.getLocalReferencedName + (translationContext(), name); if (localReferencedName == null) { return null; } - return generateCorrectReference(expression, localReferencedName); + return localReferencedName.makeRef(); } - @NotNull - private JsNameRef generateCorrectReference(@NotNull JetSimpleNameExpression expression, - @NotNull JsName referencedName) { - JsNameRef result; - if (requiresNamespaceQualifier(referencedName)) { - result = translationContext().getNamespaceQualifiedReference(referencedName); - } else { - result = referencedName.makeRef(); - if (requiresThisQualifier(expression)) { - result.setQualifier(new JsThisRef()); - } - } - return result; - } - - private boolean requiresNamespaceQualifier(@NotNull JsName referencedName) { - return translationContext().namespaceScope().ownsName(referencedName); - } - - private boolean requiresThisQualifier(@NotNull JetSimpleNameExpression expression) { - boolean isClassMember = translationContext().classScope().ownsName(getLocalReferencedName(expression)); - boolean isBackingFieldAccess = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER; - return isClassMember || isBackingFieldAccess; - } - - @Nullable - private JsName getLocalReferencedName(@NotNull JetSimpleNameExpression expression) { - String referencedName = expression.getReferencedName(); - return translationContext().enclosingScope().findExistingName(referencedName); - } - - } diff --git a/translator/src/org/jetbrains/k2js/translate/Translation.java b/translator/src/org/jetbrains/k2js/translate/Translation.java index ee9cf594979..27b8e3631ab 100644 --- a/translator/src/org/jetbrains/k2js/translate/Translation.java +++ b/translator/src/org/jetbrains/k2js/translate/Translation.java @@ -1,17 +1,20 @@ package org.jetbrains.k2js.translate; -import com.google.dart.compiler.backend.js.ast.JsExpression; -import com.google.dart.compiler.backend.js.ast.JsNode; -import com.google.dart.compiler.backend.js.ast.JsStatement; +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.resolve.BindingContext; +import org.jetbrains.k2js.declarations.Declarations; /** * @author Talanov Pavel *

- * This class is a factory for obtaining instances of translators. + * This class provides a interface which all translators use to interact with each other. + * Goal is to simlify interaction between translators. */ public final class Translation { @@ -31,8 +34,9 @@ public final class Translation { } @NotNull - static public NamespaceTranslator namespaceTranslator(@NotNull TranslationContext context) { - return NamespaceTranslator.newInstance(context); + static public JsStatement translateNamespace(@NotNull JetNamespace namespace, + @NotNull TranslationContext context) { + return NamespaceTranslator.translate(context, namespace); } @NotNull @@ -45,11 +49,6 @@ public final class Translation { return OperationTranslator.newInstance(context); } - @NotNull - static public NamespaceDeclarationTranslator declarationTranslator(@NotNull TranslationContext context) { - return NamespaceDeclarationTranslator.newInstance(context); - } - @NotNull static public PatternTranslator patternTranslator(@NotNull TranslationContext context) { return PatternTranslator.newInstance(context); @@ -79,4 +78,20 @@ public final class Translation { static public JsNode translateWhenExpression(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) { return WhenTranslator.translateWhenExpression(expression, context); } + + @NotNull + static public JsNameRef generateCorrectReference(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression, + @NotNull JsName referencedName) { + return (new ReferenceProvider(context, expression, referencedName)).generateCorrectReference(); + } + + public static void generateAst(@NotNull JsProgram result, @NotNull BindingContext bindingContext, + @NotNull Declarations declarations, @NotNull JetNamespace namespace) { + JsBlock block = result.getFragmentBlock(0); + TranslationContext context = TranslationContext.rootContext(result, bindingContext, declarations); + block.addStatement(Translation.translateNamespace(namespace, context)); + } + + } diff --git a/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java new file mode 100644 index 00000000000..235ce06ceca --- /dev/null +++ b/translator/src/org/jetbrains/k2js/translate/TranslationUtils.java @@ -0,0 +1,42 @@ +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.annotations.Nullable; +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; + +/** + * @author Talanov Pavel + */ +public final class TranslationUtils { + + @NotNull + static public JsBinaryOperation notNullCheck(@NotNull TranslationContext context, + @NotNull JsExpression expressionToCheck) { + JsNullLiteral nullLiteral = context.program().getNullLiteral(); + return AstUtil.notEqual(expressionToCheck, nullLiteral); + } + + @NotNull + static public JsBinaryOperation isNullCheck(@NotNull TranslationContext context, + @NotNull JsExpression expressionToCheck) { + JsNullLiteral nullLiteral = context.program().getNullLiteral(); + return AstUtil.equals(expressionToCheck, nullLiteral); + } + + @NotNull + static public JsNameRef getReference(@NotNull TranslationContext context, + @NotNull JetSimpleNameExpression expression, + @NotNull JsName referencedName) { + return (new ReferenceProvider(context, expression, referencedName)).generateCorrectReference(); + } + + + @Nullable + static public JsName getLocalReferencedName(@NotNull TranslationContext context, + @NotNull String name) { + return context.enclosingScope().findExistingName(name); + } + +} diff --git a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java index 26c34290dc2..0dfd90ca38c 100644 --- a/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java +++ b/translator/src/org/jetbrains/k2js/translate/TranslatorVisitor.java @@ -2,6 +2,8 @@ package org.jetbrains.k2js.translate; import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsName; +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.*; @@ -22,6 +24,15 @@ public class TranslatorVisitor extends JetVisitor { throw new RuntimeException("Unsupported expression encountered:" + expression.toString()); } + @NotNull + protected JsNameRef backingFieldReference(@NotNull JetProperty expression, @NotNull TranslationContext context) { + JsName backingFieldName = getBackingFieldName(getPropertyName(expression), context); + if (BindingUtils.belongsToNamespace(context.bindingContext(), expression)) { + return context.getNamespaceQualifiedReference(backingFieldName); + } + return AstUtil.thisQualifiedReference(backingFieldName); + } + @NotNull protected String getPropertyName(@NotNull JetProperty expression) { String propertyName = expression.getName(); @@ -32,7 +43,7 @@ public class TranslatorVisitor extends JetVisitor { } @NotNull - protected JsName getBackingFieldName(@NotNull String propertyName, @NotNull TranslationContext context) { + private JsName getBackingFieldName(@NotNull String propertyName, @NotNull TranslationContext context) { String backingFieldName = Namer.getKotlinBackingFieldName(propertyName); return context.enclosingScope().findExistingName(backingFieldName); } diff --git a/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java b/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java index 9f71f74af2e..ea60ed9c5d8 100644 --- a/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/WhenTranslator.java @@ -12,7 +12,6 @@ import java.util.List; /** * @author Talanov Pavel */ -//TODO: fix members order public class WhenTranslator extends AbstractTranslator { @NotNull @@ -70,6 +69,11 @@ public class WhenTranslator extends AbstractTranslator { return result; } + @NotNull + private JsVars generateInitStatement() { + return AstUtil.newVar(dummyCounterName, translationContext().program().getNumberLiteral(0)); + } + @NotNull private JsBinaryOperation generateConditionStatement() { JsNumberLiteral entriesNumber = program().getNumberLiteral(whenExpression.getEntries().size()); @@ -81,11 +85,6 @@ public class WhenTranslator extends AbstractTranslator { return new JsPrefixOperation(JsUnaryOperator.INC, dummyCounterName.makeRef()); } - @NotNull - private JsVars generateInitStatement() { - return AstUtil.newVar(dummyCounterName, translationContext().program().getNumberLiteral(0)); - } - @NotNull private JsStatement translateEntry(@NotNull JetWhenEntry entry) { JsStatement statementToExecute = translateExpressionToExecute(entry); @@ -103,7 +102,6 @@ public class WhenTranslator extends AbstractTranslator { return Translation.translateAsStatement(expressionToExecute, translationContext()); } - //TODO: ask what these conditions mean @NotNull private JsExpression translateConditions(@NotNull JetWhenEntry entry) { List conditions = new ArrayList(); @@ -127,11 +125,10 @@ public class WhenTranslator extends AbstractTranslator { @NotNull private JsExpression addCaseCondition(@Nullable JsExpression current, @NotNull JsExpression condition) { if (current == null) { - current = condition; + return condition; } else { - current = new JsBinaryOperation(JsBinaryOperator.OR, current, condition); + return AstUtil.or(current, condition); } - return current; } @@ -140,9 +137,27 @@ public class WhenTranslator extends AbstractTranslator { if (condition instanceof JetWhenConditionIsPattern) { return translatePatternCondition((JetWhenConditionIsPattern) condition); } + if (condition instanceof JetWhenConditionCall) { + return translateCallCondition((JetWhenConditionCall) condition); + } throw new AssertionError("Unsupported when condition " + condition.getClass()); } + @NotNull + private JsExpression translateCallCondition(@NotNull JetWhenConditionCall condition) { + JsExpression suffixExpression = + Translation.translateAsExpression(getSuffixExpression(condition), translationContext()); + AstUtil.setQualifier(suffixExpression, expressionToMatch); + return AstUtil.equalsTrue(suffixExpression, translationContext().program()); + } + + @NotNull + private JetExpression getSuffixExpression(@NotNull JetWhenConditionCall condition) { + JetExpression suffixExpression = condition.getCallSuffixExpression(); + assert suffixExpression != null : "When call condition should have suffix expression"; + return suffixExpression; + } + @NotNull private JsBlock addDummyBreak(@NotNull JsStatement statement) { return AstUtil.newBlock(statement, new JsBreak()); diff --git a/translator/src/org/jetbrains/k2js/utils/ClassSorter.java b/translator/src/org/jetbrains/k2js/utils/ClassSorter.java new file mode 100644 index 00000000000..cd43068fe3a --- /dev/null +++ b/translator/src/org/jetbrains/k2js/utils/ClassSorter.java @@ -0,0 +1,83 @@ +package org.jetbrains.k2js.utils; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.k2js.translate.BindingUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Talanov Pavel + */ +public final class ClassSorter { + + @NotNull + private final List classesToSort; + @NotNull + private final List descriptorList; + @NotNull + private final BindingContext bindingContext; + @NotNull + private final PartiallyOrderedSet partiallyOrderedSet = new PartiallyOrderedSet(); + + @NotNull + static public List sortUsingInheritanceOrder(@NotNull List original, + @NotNull BindingContext bindingContext) { + ClassSorter sorter = new ClassSorter(original, bindingContext); + return sorter.sortUsingInheritanceOrder(); + } + + private ClassSorter(@NotNull List original, @NotNull BindingContext bindingContext) { + this.classesToSort = original; + this.bindingContext = bindingContext; + this.descriptorList = getDescriptorList(); + } + + @NotNull + private List sortUsingInheritanceOrder() { + putDescriptorsInPartiallyOrderedSet(); + setInheritanceOrder(); + return getSortedClasses(); + } + + @NotNull + private List getSortedClasses() { + List sortedClasses = new ArrayList(); + for (Object object : partiallyOrderedSet) { + assert object instanceof ClassDescriptor; + sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, (ClassDescriptor) object)); + } + return sortedClasses; + } + + private void putDescriptorsInPartiallyOrderedSet() { + partiallyOrderedSet.addAll(descriptorList); + } + + private void setInheritanceOrder() { + for (ClassDescriptor descriptor : getDescriptorList()) { + traverseAncestorsAndSetOrder(descriptor); + } + } + + @NotNull + private List getDescriptorList() { + List descriptorList = new ArrayList(); + for (JetClass jetClass : classesToSort) { + descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass)); + } + return descriptorList; + } + + private void traverseAncestorsAndSetOrder(@NotNull ClassDescriptor descriptor) { + List superclasses = BindingUtils.getSuperclassDescriptors(descriptor); + for (ClassDescriptor superclass : superclasses) { + partiallyOrderedSet.setOrdering(superclass, descriptor); + traverseAncestorsAndSetOrder(superclass); + } + } + +} diff --git a/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java b/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java new file mode 100644 index 00000000000..fdee94213b7 --- /dev/null +++ b/translator/src/org/jetbrains/k2js/utils/DiGraphNode.java @@ -0,0 +1,170 @@ +package org.jetbrains.k2js.utils; + +/* + * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A node in a directed graph. In addition to an arbitrary + * Object containing user data associated with the node, + * each node maintains a Sets of nodes which are pointed + * to by the current node (available from getOutNodes). + * The in-degree of the node (that is, number of nodes that point to + * the current node) may be queried. + */ +class DiGraphNode implements Cloneable, Serializable { + + /** + * The data associated with this node. + */ + protected Object data; + + /** + * A Set of neighboring nodes pointed to by this + * node. + */ + protected Set outNodes = new HashSet(); + + /** + * The in-degree of the node. + */ + protected int inDegree = 0; + + /** + * A Set of neighboring nodes that point to this + * node. + */ + private Set inNodes = new HashSet(); + + public DiGraphNode(Object data) { + this.data = data; + } + + /** + * Returns the Object referenced by this node. + */ + public Object getData() { + return data; + } + + /** + * Returns an Iterator containing the nodes pointed + * to by this node. + */ + public Iterator getOutNodes() { + return outNodes.iterator(); + } + + /** + * Adds a directed edge to the graph. The outNodes list of this + * node is updated and the in-degree of the other node is incremented. + * + * @param node a DiGraphNode. + * @return true if the node was not previously the + * target of an edge. + */ + public boolean addEdge(DiGraphNode node) { + if (outNodes.contains(node)) { + return false; + } + + outNodes.add(node); + node.inNodes.add(this); + node.incrementInDegree(); + return true; + } + + /** + * Returns true if an edge exists between this node + * and the given node. + * + * @param node a DiGraphNode. + * @return true if the node is the target of an edge. + */ + public boolean hasEdge(DiGraphNode node) { + return outNodes.contains(node); + } + + /** + * Removes a directed edge from the graph. The outNodes list of this + * node is updated and the in-degree of the other node is decremented. + * + * @return true if the node was previously the target + * of an edge. + */ + public boolean removeEdge(DiGraphNode node) { + if (!outNodes.contains(node)) { + return false; + } + + outNodes.remove(node); + node.inNodes.remove(this); + node.decrementInDegree(); + return true; + } + + /** + * Removes this node from the graph, updating neighboring nodes + * appropriately. + */ + public void dispose() { + Object[] inNodesArray = inNodes.toArray(); + for (int i = 0; i < inNodesArray.length; i++) { + DiGraphNode node = (DiGraphNode) inNodesArray[i]; + node.removeEdge(this); + } + + Object[] outNodesArray = outNodes.toArray(); + for (int i = 0; i < outNodesArray.length; i++) { + DiGraphNode node = (DiGraphNode) outNodesArray[i]; + removeEdge(node); + } + } + + /** + * Returns the in-degree of this node. + */ + public int getInDegree() { + return inDegree; + } + + /** + * Increments the in-degree of this node. + */ + private void incrementInDegree() { + ++inDegree; + } + + /** + * Decrements the in-degree of this node. + */ + private void decrementInDegree() { + --inDegree; + } +} \ No newline at end of file diff --git a/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java b/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java new file mode 100644 index 00000000000..d1bc45a0c9d --- /dev/null +++ b/translator/src/org/jetbrains/k2js/utils/PartiallyOrderedSet.java @@ -0,0 +1,209 @@ +package org.jetbrains.k2js.utils; + +/* + * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.util.*; + +/** + * A set of Objects with pairwise orderings between them. + * The iterator method provides the elements in + * topologically sorted order. Elements participating in a cycle + * are not returned. + *

+ * Unlike the SortedSet and SortedMap + * interfaces, which require their elements to implement the + * Comparable interface, this class receives ordering + * information via its setOrdering and + * unsetPreference methods. This difference is due to + * the fact that the relevant ordering between elements is unlikely to + * be inherent in the elements themselves; rather, it is set + * dynamically accoring to application policy. For example, in a + * service provider registry situation, an application might allow the + * user to set a preference order for service provider objects + * supplied by a trusted vendor over those supplied by another. + */ +class PartiallyOrderedSet extends AbstractSet { + + // The topological sort (roughly) follows the algorithm described in + // Horowitz and Sahni, _Fundamentals of Data Structures_ (1976), + // p. 315. + + // Maps Objects to DigraphNodes that contain them + private Map poNodes = new HashMap(); + + // The set of Objects + private Set nodes = poNodes.keySet(); + + /** + * Constructs a PartiallyOrderedSet. + */ + public PartiallyOrderedSet() { + } + + public int size() { + return nodes.size(); + } + + public boolean contains(Object o) { + return nodes.contains(o); + } + + /** + * Returns an iterator over the elements contained in this + * collection, with an ordering that respects the orderings set + * by the setOrdering method. + */ + public Iterator iterator() { + return new PartialOrderIterator(poNodes.values().iterator()); + } + + /** + * Adds an Object to this + * PartiallyOrderedSet. + */ + public boolean add(Object o) { + if (nodes.contains(o)) { + return false; + } + + DiGraphNode node = new DiGraphNode(o); + poNodes.put(o, node); + return true; + } + + /** + * Removes an Object from this + * PartiallyOrderedSet. + */ + public boolean remove(Object o) { + DiGraphNode node = (DiGraphNode) poNodes.get(o); + if (node == null) { + return false; + } + + poNodes.remove(o); + node.dispose(); + return true; + } + + public void clear() { + poNodes.clear(); + } + + /** + * Sets an ordering between two nodes. When an iterator is + * requested, the first node will appear earlier in the + * sequence than the second node. If a prior ordering existed + * between the nodes in the opposite order, it is removed. + * + * @return true if no prior ordering existed + * between the nodes, falseotherwise. + */ + public boolean setOrdering(Object first, Object second) { + DiGraphNode firstPONode = + (DiGraphNode) poNodes.get(first); + DiGraphNode secondPONode = + (DiGraphNode) poNodes.get(second); + + secondPONode.removeEdge(firstPONode); + return firstPONode.addEdge(secondPONode); + } + + /** + * Removes any ordering between two nodes. + * + * @return true if a prior prefence existed between the nodes. + */ + public boolean unsetOrdering(Object first, Object second) { + DiGraphNode firstPONode = + (DiGraphNode) poNodes.get(first); + DiGraphNode secondPONode = + (DiGraphNode) poNodes.get(second); + + return firstPONode.removeEdge(secondPONode) || + secondPONode.removeEdge(firstPONode); + } + + /** + * Returns true if an ordering exists between two + * nodes. + */ + public boolean hasOrdering(Object preferred, Object other) { + DiGraphNode preferredPONode = + (DiGraphNode) poNodes.get(preferred); + DiGraphNode otherPONode = + (DiGraphNode) poNodes.get(other); + + return preferredPONode.hasEdge(otherPONode); + } +} + +class PartialOrderIterator implements Iterator { + + LinkedList zeroList = new LinkedList(); + Map inDegrees = new HashMap(); // DiGraphNode -> Integer + + public PartialOrderIterator(Iterator iter) { + // Initialize scratch in-degree values, zero list + while (iter.hasNext()) { + DiGraphNode node = (DiGraphNode) iter.next(); + int inDegree = node.getInDegree(); + inDegrees.put(node, new Integer(inDegree)); + + // Add nodes with zero in-degree to the zero list + if (inDegree == 0) { + zeroList.add(node); + } + } + } + + public boolean hasNext() { + return !zeroList.isEmpty(); + } + + public Object next() { + DiGraphNode first = (DiGraphNode) zeroList.removeFirst(); + + // For each out node of the output node, decrement its in-degree + Iterator outNodes = first.getOutNodes(); + while (outNodes.hasNext()) { + DiGraphNode node = (DiGraphNode) outNodes.next(); + int inDegree = ((Integer) inDegrees.get(node)).intValue() - 1; + inDegrees.put(node, new Integer(inDegree)); + + // If the in-degree has fallen to 0, place the node on the list + if (inDegree == 0) { + zeroList.add(node); + } + } + + return first.getData(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/translator/test/org/jetbrains/k2js/test/AbstractExpressionTest.java b/translator/test/org/jetbrains/k2js/test/AbstractExpressionTest.java index bb96c99a92a..58e33655e39 100644 --- a/translator/test/org/jetbrains/k2js/test/AbstractExpressionTest.java +++ b/translator/test/org/jetbrains/k2js/test/AbstractExpressionTest.java @@ -1,8 +1,5 @@ package org.jetbrains.k2js.test; -import java.util.Arrays; -import java.util.List; - /** * @author Talanov Pavel */ @@ -10,11 +7,6 @@ public abstract class AbstractExpressionTest extends TranslationTest { private final String SUITE = "expression/"; - @Override - protected List generateFilenameList(String inputFile) { - return Arrays.asList(inputFile); - } - @Override protected String suiteDirectoryName() { return SUITE; diff --git a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java index efcad3444ce..8bb10e7019e 100644 --- a/translator/test/org/jetbrains/k2js/test/BasicClassTest.java +++ b/translator/test/org/jetbrains/k2js/test/BasicClassTest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public class BasicClassTest extends IncludeLibraryTest { +public class BasicClassTest extends TranslationTest { final private static String MAIN = "class/"; @@ -24,7 +24,7 @@ public class BasicClassTest extends IncludeLibraryTest { testFooBoxIsTrue("methodDeclarationAndCall.kt"); } - //TODO: wait for bugfix and implement properties as consructor parameter declaration + //TODO: wait for bugfix and implement properties as constructor parameter declaration @Test public void constructorWithParameter() throws Exception { testFooBoxIsTrue("constructorWithParameter.kt"); @@ -44,4 +44,9 @@ public class BasicClassTest extends IncludeLibraryTest { public void complexExpressionAsConstructorParameter() throws Exception { testFooBoxIsTrue("complexExpressionAsConstructorParameter.kt"); } + + @Test + public void propertyAccess() throws Exception { + testFooBoxIsTrue("propertyAccess.kt"); + } } diff --git a/translator/test/org/jetbrains/k2js/test/ClassInheritanceTest.java b/translator/test/org/jetbrains/k2js/test/ClassInheritanceTest.java index 247cf7e1b39..b9cae04b922 100644 --- a/translator/test/org/jetbrains/k2js/test/ClassInheritanceTest.java +++ b/translator/test/org/jetbrains/k2js/test/ClassInheritanceTest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public final class ClassInheritanceTest extends IncludeLibraryTest { +public final class ClassInheritanceTest extends TranslationTest { final private static String MAIN = "inheritance/"; @@ -38,6 +38,16 @@ public final class ClassInheritanceTest extends IncludeLibraryTest { public void valuePassedToAncestorConstructor() throws Exception { testFooBoxIsTrue("valuePassedToAncestorConstructor.kt"); } + + @Test + public void baseClassDefinedAfterDerived() throws Exception { + testFooBoxIsTrue("baseClassDefinedAfterDerived.kt"); + } + + @Test + public void definitionOrder() throws Exception { + testFooBoxIsTrue("definitionOrder.kt"); + } } diff --git a/translator/test/org/jetbrains/k2js/test/IncludeLibraryTest.java b/translator/test/org/jetbrains/k2js/test/IncludeLibraryTest.java deleted file mode 100644 index 4b87608a5f6..00000000000 --- a/translator/test/org/jetbrains/k2js/test/IncludeLibraryTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jetbrains.k2js.test; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Talanov Pavel - */ -public abstract class IncludeLibraryTest extends TranslationTest { - - @Override - protected List generateFilenameList(String inputFile) { - return Arrays.asList(kotlinLibraryPath(), inputFile); - } - -} diff --git a/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java b/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java index 9fd8b52ce4f..3c393a51d4f 100644 --- a/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java +++ b/translator/test/org/jetbrains/k2js/test/KotlinLibTest.java @@ -7,7 +7,6 @@ import org.mozilla.javascript.Scriptable; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -17,11 +16,6 @@ public class KotlinLibTest extends TranslationTest { final private static String MAIN = "kotlinLib/"; - @Override - protected List generateFilenameList(String inputFile) { - return Arrays.asList(kotlinLibraryPath()); - } - @Override protected String mainDirectory() { return MAIN; @@ -50,6 +44,14 @@ public class KotlinLibTest extends TranslationTest { runPropertyTypeCheck("Class", propertyToType); } + @Test + public void namespaceObjectHasCreateMethod() throws Exception { + final Map> propertyToType + = new HashMap>(); + propertyToType.put("create", Function.class); + runPropertyTypeCheck("Namespace", propertyToType); + } + @Test public void traitObjectHasCreateMethod() throws Exception { final Map> propertyToType @@ -66,6 +68,27 @@ public class KotlinLibTest extends TranslationTest { new RhinoPropertyTypesChecker("foo", propertyToType)); } + @Test + public void createdNamespaceIsJSObject() throws Exception { + final Map> propertyToType + = new HashMap>(); + runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("namespace.js")), + new RhinoPropertyTypesChecker("foo", propertyToType)); + } + + @Test + public void namespaceHasDeclaredFunction() throws Exception { + runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("namespace.js")), + new RhinoFunctionResultChecker("test", true)); + } + + + @Test + public void namespaceHasDeclaredClasses() throws Exception { + runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("namespaceWithClasses.js")), + new RhinoFunctionResultChecker("test", true)); + } + @Test public void isSameType() throws Exception { runRhinoTest(Arrays.asList(kotlinLibraryPath(), cases("isSameType.js")), diff --git a/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java new file mode 100644 index 00000000000..2c72d645120 --- /dev/null +++ b/translator/test/org/jetbrains/k2js/test/OperatorOverloadingTest.java @@ -0,0 +1,21 @@ +package org.jetbrains.k2js.test; + +import org.junit.Test; + +/** + * @author Talanov Pavel + */ +public class OperatorOverloadingTest extends TranslationTest { + + final private static String MAIN = "operatorOverloading/"; + + @Override + protected String mainDirectory() { + return MAIN; + } + + @Test + public void plusOverload() throws Exception { + testFooBoxIsTrue("plusOverload.kt"); + } +} diff --git a/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java b/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java index 74d0996ba70..eb8c2f78d96 100644 --- a/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java +++ b/translator/test/org/jetbrains/k2js/test/PatternMatchingTest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public final class PatternMatchingTest extends IncludeLibraryTest { +public final class PatternMatchingTest extends TranslationTest { final private static String MAIN = "patternMatching/"; @@ -49,4 +49,19 @@ public final class PatternMatchingTest extends IncludeLibraryTest { testFunctionOutput("multipleCases.kt", "foo", "box", 2.0); } + @Test + public void matchNullableType() throws Exception { + testFooBoxIsTrue("matchNullableType.kt"); + } + + @Test + public void whenConditionMethodCall() throws Exception { + testFooBoxIsTrue("whenConditionMethodCall.kt"); + } + + @Test + public void whenConditionPropertyAccess() throws Exception { + testFooBoxIsTrue("whenConditionPropertyAccess.kt"); + } + } diff --git a/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java b/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java index 3052216e426..a57e4062b09 100644 --- a/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java +++ b/translator/test/org/jetbrains/k2js/test/PropertyAccessorTest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public final class PropertyAccessorTest extends IncludeLibraryTest { +public final class PropertyAccessorTest extends TranslationTest { final private static String MAIN = "propertyAccess/"; @@ -49,6 +49,16 @@ public final class PropertyAccessorTest extends IncludeLibraryTest { testFooBoxIsTrue("safeCallReturnsNullIfFails.kt"); } + @Test + public void namespacePropertyInitializer() throws Exception { + testFooBoxIsTrue("namespacePropertyInitializer.kt"); + } + + @Test + public void namespacePropertySet() throws Exception { + testFooBoxIsTrue("namespacePropertySet.kt"); + } + //TODO test // @Test // public void namespaceCustomAccessors() throws Exception { diff --git a/translator/test/org/jetbrains/k2js/test/RTTITest.java b/translator/test/org/jetbrains/k2js/test/RTTITest.java index 0fa4ddc4d0f..1c36a765d56 100644 --- a/translator/test/org/jetbrains/k2js/test/RTTITest.java +++ b/translator/test/org/jetbrains/k2js/test/RTTITest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public class RTTITest extends IncludeLibraryTest { +public class RTTITest extends TranslationTest { final private static String MAIN = "rtti/"; diff --git a/translator/test/org/jetbrains/k2js/test/RhinoFunctionResultChecker.java b/translator/test/org/jetbrains/k2js/test/RhinoFunctionResultChecker.java index 8be5474e5bc..115a46173aa 100644 --- a/translator/test/org/jetbrains/k2js/test/RhinoFunctionResultChecker.java +++ b/translator/test/org/jetbrains/k2js/test/RhinoFunctionResultChecker.java @@ -2,8 +2,6 @@ package org.jetbrains.k2js.test; import org.jetbrains.annotations.Nullable; import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.Scriptable; import static org.junit.Assert.assertTrue; @@ -29,43 +27,22 @@ public final class RhinoFunctionResultChecker implements RhinoResultChecker { @Override public void runChecks(Context context, Scriptable scope) throws Exception { - Object result = extractAndCallFunctionObject(namespaceName, functionName, context, scope); + Object result = evaluateFunction(context, scope); assertTrue("Result is not what expected! Expected: " + expectedResult + " Evaluated : " + result, result.equals(expectedResult)); String report = namespaceName + "." + functionName + "() = " + Context.toString(result); System.out.println(report); } - private Object extractAndCallFunctionObject(String namespaceName, String functionName, - Context cx, Scriptable scope) { - Object functionObject; + private Object evaluateFunction(Context cx, Scriptable scope) { + return cx.evaluateString(scope, functionCallString(), "function call", 0, null); + } + + private String functionCallString() { + String result = functionName + "()"; if (namespaceName != null) { - functionObject = extractFunctionFromObject(namespaceName, functionName, scope); - } else { - functionObject = extractFunctionFromGlobalScope(functionName, scope); + result = namespaceName + "." + result; } - return callFunctionAndCheckResults(cx, scope, (Function) functionObject); - } - - private Object callFunctionAndCheckResults(Context cx, Scriptable scope, Function functionObject) { - Object functionArgs[] = {}; - return functionObject.call(cx, scope, scope, functionArgs); - } - - private Object extractFunctionFromGlobalScope(String functionName, Scriptable scope) { - Object functionObject; - functionObject = scope.get(functionName, scope); - assertTrue("Function " + functionName + " is not defined in global scope", - functionObject instanceof Function); - return functionObject; - } - - private Object extractFunctionFromObject(String namespaceName, String functionName, Scriptable scope) { - Object functionObject; - NativeObject namespaceObject = RhinoUtils.extractObject(namespaceName, scope); - functionObject = namespaceObject.get(functionName, namespaceObject); - assertTrue("Function " + functionName + " is not defined in namespace " + namespaceName, - functionObject instanceof Function); - return functionObject; + return result; } } diff --git a/translator/test/org/jetbrains/k2js/test/TraitTest.java b/translator/test/org/jetbrains/k2js/test/TraitTest.java index d8346238200..7059564b7e8 100644 --- a/translator/test/org/jetbrains/k2js/test/TraitTest.java +++ b/translator/test/org/jetbrains/k2js/test/TraitTest.java @@ -5,7 +5,7 @@ import org.junit.Test; /** * @author Talanov Pavel */ -public final class TraitTest extends IncludeLibraryTest { +public final class TraitTest extends TranslationTest { final private static String MAIN = "trait/"; @@ -49,5 +49,10 @@ public final class TraitTest extends IncludeLibraryTest { testFooBoxIsOk("funDelegation.jet"); } + @Test + public void definitionOrder() throws Exception { + testFooBoxIsTrue("definitionOrder.kt"); + } + } diff --git a/translator/test/org/jetbrains/k2js/test/TranslationTest.java b/translator/test/org/jetbrains/k2js/test/TranslationTest.java index ae1ddbd0b58..7cbad97c0aa 100644 --- a/translator/test/org/jetbrains/k2js/test/TranslationTest.java +++ b/translator/test/org/jetbrains/k2js/test/TranslationTest.java @@ -5,6 +5,7 @@ import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; import java.io.FileReader; +import java.util.Arrays; import java.util.List; @@ -16,7 +17,7 @@ public abstract class TranslationTest { final protected static String TEST_FILES = "testFiles/"; final private static String CASES = "cases/"; final private static String OUT = "out/"; - final private String KOTLIN_JS_LIB = TEST_FILES + "kotlin_lib.js"; + final private static String KOTLIN_JS_LIB = TEST_FILES + "kotlin_lib.js"; protected abstract String mainDirectory(); @@ -62,7 +63,9 @@ public abstract class TranslationTest { K2JSTranslator.translate(args); } - abstract protected List generateFilenameList(String inputfile); + protected List generateFilenameList(String inputFile) { + return Arrays.asList(kotlinLibraryPath(), inputFile); + } //TODO: refactor filename generation logic private String getOutputFilePath(String filename) { @@ -87,10 +90,10 @@ public abstract class TranslationTest { reader.close(); } - protected void runRhinoTest(List filenames, RhinoResultChecker checker) throws Exception { + protected void runRhinoTest(List fileNames, RhinoResultChecker checker) throws Exception { Context cx = Context.enter(); Scriptable scope = cx.initStandardObjects(); - for (String filename : filenames) { + for (String filename : fileNames) { runFileWithRhino(filename, cx, scope); } checker.runChecks(cx, scope); diff --git a/translator/test/org/jetbrains/k2js/test/TupleTest.java b/translator/test/org/jetbrains/k2js/test/TupleTest.java index 4e8fab2ad21..3e2a66b9363 100644 --- a/translator/test/org/jetbrains/k2js/test/TupleTest.java +++ b/translator/test/org/jetbrains/k2js/test/TupleTest.java @@ -3,7 +3,7 @@ package org.jetbrains.k2js.test; /** * @author Talanov Pavel */ -public class TupleTest extends IncludeLibraryTest { +public class TupleTest extends TranslationTest { final private static String MAIN = "tuple/"; diff --git a/translator/testFiles/class/cases/propertyAccess.kt b/translator/testFiles/class/cases/propertyAccess.kt new file mode 100644 index 00000000000..d7f6475999d --- /dev/null +++ b/translator/testFiles/class/cases/propertyAccess.kt @@ -0,0 +1,9 @@ +namespace foo + +class Test() { + val p = true +} + +fun box() : Boolean { + return Test().p +} \ No newline at end of file diff --git a/translator/testFiles/expression/function/cases/loopClosure.kt b/translator/testFiles/expression/function/cases/loopClosure.kt index 5c5a1e5615d..fcffa4a0f85 100644 --- a/translator/testFiles/expression/function/cases/loopClosure.kt +++ b/translator/testFiles/expression/function/cases/loopClosure.kt @@ -5,7 +5,7 @@ var b = 0 fun loop(var times : Int) { while(times > 0) { val u : fun(value : Int) : Unit = { - b++ + b = b + 1 } u(times--) } diff --git a/translator/testFiles/inheritance/cases/baseClassDefinedAfterDerived.kt b/translator/testFiles/inheritance/cases/baseClassDefinedAfterDerived.kt new file mode 100644 index 00000000000..9ef882ca38e --- /dev/null +++ b/translator/testFiles/inheritance/cases/baseClassDefinedAfterDerived.kt @@ -0,0 +1,13 @@ +namespace foo + + +class A() : B() { + +} + +open class B() { + + val a = 3 +} + +fun box() = (A().a == 3) \ No newline at end of file diff --git a/translator/testFiles/inheritance/cases/definitionOrder.kt b/translator/testFiles/inheritance/cases/definitionOrder.kt new file mode 100644 index 00000000000..1f57193674f --- /dev/null +++ b/translator/testFiles/inheritance/cases/definitionOrder.kt @@ -0,0 +1,37 @@ +namespace foo + +class C() : B() { + { + order = order + "C" + } +} + +class D() : B() { + { + order = order + "D" + } +} + +class E() : A() { + { + order = order + "E" + } +} + +open class B() : A() { + { + order = order + "B" + } +} + +open class A() { + + var order = "" + { + order = order + "A" + } +} + +fun box() : Boolean { + return (C().order == "ABC") && (D().order == "ABD") && (E().order == "AE") +} \ No newline at end of file diff --git a/translator/testFiles/kotlinLib/cases/namespace.js b/translator/testFiles/kotlinLib/cases/namespace.js new file mode 100644 index 00000000000..4e028424b2f --- /dev/null +++ b/translator/testFiles/kotlinLib/cases/namespace.js @@ -0,0 +1,10 @@ +foo = Namespace.create({initialize:function(){ +} +, box:function(){ + return !false; +} +}); + +function test() { + return foo.box() +} diff --git a/translator/testFiles/kotlinLib/cases/namespaceWithClasses.js b/translator/testFiles/kotlinLib/cases/namespaceWithClasses.js new file mode 100644 index 00000000000..4d85b782583 --- /dev/null +++ b/translator/testFiles/kotlinLib/cases/namespaceWithClasses.js @@ -0,0 +1,45 @@ +{ + classes = function(){ + var A = Class.create({initialize:function(){ + this.$order = ''; + { + this.set_order(this.get_order() + 'A'); + } + } + , set_order:function(tmp$0){ + this.$order = tmp$0; + } + , get_order:function(){ + return this.$order; + } + }); + var B = Class.create(A, {initialize:function(){ + this.super_init(); + { + this.set_order(this.get_order() + 'B'); + } + } + }); + var C = Class.create(B, {initialize:function(){ + this.super_init(); + { + this.set_order(this.get_order() + 'C'); + } + } + }); + return {A:A, B:B, C:C}; + } + (); + foo = Namespace.create(classes, {initialize:function(){ + } + , box:function(){ + return (new foo.C).get_order() === 'ABC' && (new foo.B).get_order() === 'AB' && (new foo.A).get_order() === 'A'; + } + }); +} + + + +function test() { + return foo.box() +} diff --git a/translator/testFiles/kotlin_lib.js b/translator/testFiles/kotlin_lib.js index 9eccea4f81b..dbcfa033e93 100644 --- a/translator/testFiles/kotlin_lib.js +++ b/translator/testFiles/kotlin_lib.js @@ -6,9 +6,9 @@ function $A(iterable) { return results; } -var isType = function(object, class) { +var isType = function(object, klass) { current = object.get_class(); - while (current !== class) { + while (current !== klass) { if (current === null) { return false; } @@ -101,7 +101,6 @@ var Class = (function() { var Trait = (function() { - function add(object, source) { properties = Object.keys(source); for (var i = 0, length = properties.length; i < length; i++) { @@ -127,6 +126,18 @@ var Trait = (function() { }; })(); + + +var Namespace = (function() { + + function create() { + return Trait.create.apply(Trait, arguments); + } + return { + create: create + }; +})(); + (function() { var _toString = Object.prototype.toString, diff --git a/translator/testFiles/operatorOverloading/cases/plusOverload.kt b/translator/testFiles/operatorOverloading/cases/plusOverload.kt new file mode 100644 index 00000000000..3b7a0e718a1 --- /dev/null +++ b/translator/testFiles/operatorOverloading/cases/plusOverload.kt @@ -0,0 +1,12 @@ +namespace foo + + class myInt(a : Int) { + val value = a; + + fun plus(other : myInt) : myInt = myInt(value + other.value) + } + +fun box() : Boolean { + + return (myInt(3) + myInt(5)).value == 8 +} \ No newline at end of file diff --git a/translator/testFiles/patternMatching/cases/matchNullableType.kt b/translator/testFiles/patternMatching/cases/matchNullableType.kt new file mode 100644 index 00000000000..65de099135a --- /dev/null +++ b/translator/testFiles/patternMatching/cases/matchNullableType.kt @@ -0,0 +1,13 @@ +namespace foo + +class A() { + +} + +fun box() : Boolean { + var a = null : A? + when(a) { + is A? => return true + else => return false + } +} \ No newline at end of file diff --git a/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt b/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt new file mode 100644 index 00000000000..4d9a470d615 --- /dev/null +++ b/translator/testFiles/patternMatching/cases/whenConditionMethodCall.kt @@ -0,0 +1,16 @@ +namespace foo + +class A() { + fun p() = true +} + +fun box() : Boolean { + var a = 0 + when(A()) { + .p() => a-- + is A? => a++; + is A => a++; + else => a++; + } + return (a == -1) +} \ No newline at end of file diff --git a/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt b/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt new file mode 100644 index 00000000000..f6ad5bb9884 --- /dev/null +++ b/translator/testFiles/patternMatching/cases/whenConditionPropertyAccess.kt @@ -0,0 +1,18 @@ +namespace foo + +class A() { + val pp = true + fun p() = true +} + +fun box() : Boolean { + var a = 0 + when(A()) { + .pp => a -=2 + .p() => a-- + is A? => a++; + is A => a++; + else => a++; + } + return (a == -2) +} \ No newline at end of file diff --git a/translator/testFiles/propertyAccess/cases/namespacePropertyInitializer.kt b/translator/testFiles/propertyAccess/cases/namespacePropertyInitializer.kt new file mode 100644 index 00000000000..01314357101 --- /dev/null +++ b/translator/testFiles/propertyAccess/cases/namespacePropertyInitializer.kt @@ -0,0 +1,5 @@ +namespace foo + +val b = 3 + +fun box() = (b == 3) \ No newline at end of file diff --git a/translator/testFiles/propertyAccess/cases/namespacePropertySet.kt b/translator/testFiles/propertyAccess/cases/namespacePropertySet.kt new file mode 100644 index 00000000000..1b602320603 --- /dev/null +++ b/translator/testFiles/propertyAccess/cases/namespacePropertySet.kt @@ -0,0 +1,8 @@ +namespace foo + +var b = 3 + +fun box() : Boolean { + b = 2 + return (b == 2) +} \ No newline at end of file diff --git a/translator/testFiles/trait/cases/definitionOrder.kt b/translator/testFiles/trait/cases/definitionOrder.kt new file mode 100644 index 00000000000..7104bdbe4aa --- /dev/null +++ b/translator/testFiles/trait/cases/definitionOrder.kt @@ -0,0 +1,41 @@ +namespace foo + +class C() : B() { + { + order = order + "C" + } +} + +class D() : B() { + { + order = order + "D" + } +} + +class E() : A() { + { + order = order + "E" + } +} + +open class B() : A(), F { + { + order = order + "B" + } +} + +open class A() : F { + + var order = "" + { + order = order + "A" + } +} + +trait F { + fun bar() = "F" +} + +fun box() : Boolean { + return (C().order == "ABC") && (D().order == "ABD") && (E().order == "AE") && (C().bar() == "F") && (A().bar() == "F") +} \ No newline at end of file