diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/JetTestFunctionDetector.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/JetTestFunctionDetector.java index cba33a8b40b..52213599460 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/JetTestFunctionDetector.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/JetTestFunctionDetector.java @@ -18,7 +18,6 @@ package org.jetbrains.k2js.translate.general; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetClass; @@ -28,8 +27,10 @@ import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; +import java.util.Collection; import java.util.List; +import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor; import static org.jetbrains.k2js.translate.utils.BindingUtils.getNullableDescriptorForFunction; /** @@ -65,8 +66,8 @@ public class JetTestFunctionDetector { return false; } - @Nullable - public static List findTestFunctions(@NotNull BindingContext bindingContext, @NotNull List files) { + @NotNull + private static List findTestFunctions(@NotNull BindingContext bindingContext, @NotNull Collection files) { List answer = Lists.newArrayList(); for (JetFile file : files) { answer.addAll(getTestFunctions(bindingContext, file.getDeclarations())); @@ -74,7 +75,16 @@ public class JetTestFunctionDetector { return answer; } - @Nullable + @NotNull + public static List getTestFunctionDescriptors(@NotNull BindingContext bindingContext, @NotNull Collection files) { + List answer = Lists.newArrayList(); + for (JetNamedFunction function : findTestFunctions(bindingContext, files)) { + answer.add(getFunctionDescriptor(bindingContext, function)); + } + return answer; + } + + @NotNull private static List getTestFunctions(@NotNull BindingContext bindingContext, @NotNull List declarations) { List answer = Lists.newArrayList(); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java index ea77ec00559..e3a657f5859 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/general/Translation.java @@ -19,12 +19,8 @@ package org.jetbrains.k2js.translate.general; import com.google.dart.compiler.backend.js.JsNamer; import com.google.dart.compiler.backend.js.JsPrettyNamer; import com.google.dart.compiler.backend.js.ast.*; -import com.google.dart.compiler.util.AstUtil; -import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.psi.*; @@ -48,11 +44,13 @@ import org.jetbrains.k2js.translate.expression.WhenTranslator; import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator; import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator; import org.jetbrains.k2js.translate.reference.CallBuilder; +import org.jetbrains.k2js.translate.test.TestGenerator; import org.jetbrains.k2js.translate.utils.JsAstUtils; +import org.jetbrains.k2js.translate.utils.TranslationUtils; import org.jetbrains.k2js.translate.utils.dangerous.DangerousData; import org.jetbrains.k2js.translate.utils.dangerous.DangerousTranslator; -import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -79,7 +77,7 @@ public final class Translation { } @NotNull - public static List translateFiles(@NotNull List files, @NotNull TranslationContext context) { + public static List translateFiles(@NotNull Collection files, @NotNull TranslationContext context) { return NamespaceDeclarationTranslator.translateFiles(files, context); } @@ -149,11 +147,11 @@ public final class Translation { @NotNull public static JsProgram generateAst(@NotNull BindingContext bindingContext, - @NotNull List files, @NotNull MainCallParameters mainCallParameters, - @NotNull Config config, List rawStatements) + @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, + @NotNull Config config) throws TranslationException { try { - return doGenerateAst(bindingContext, files, mainCallParameters, config, rawStatements); + return doGenerateAst(bindingContext, files, mainCallParameters, config); } catch (UnsupportedOperationException e) { throw new UnsupportedFeatureException("Unsupported feature used.", e); @@ -164,9 +162,9 @@ public final class Translation { } @NotNull - private static JsProgram doGenerateAst(@NotNull BindingContext bindingContext, @NotNull List files, + private static JsProgram doGenerateAst(@NotNull BindingContext bindingContext, @NotNull Collection files, @NotNull MainCallParameters mainCallParameters, - @NotNull Config config, List rawStatements) throws MainFunctionNotFoundException { + @NotNull Config config) throws MainFunctionNotFoundException { //TODO: move some of the code somewhere JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext, config.getTarget()); @@ -174,12 +172,13 @@ public final class Translation { JsBlock block = program.getGlobalBlock(); JsFunction rootFunction = JsAstUtils.createPackage(block.getStatements(), program.getScope()); - List statements = rootFunction.getBody().getStatements(); + JsBlock rootBlock = rootFunction.getBody(); + List statements = rootBlock.getStatements(); statements.add(program.getStringLiteral("use strict").makeStmt()); TranslationContext context = TranslationContext.rootContext(staticContext); statements.addAll(translateFiles(files, context)); - defineModule(statements, context, config); + TranslationUtils.defineModule(context, statements, config.getModuleId()); if (mainCallParameters.shouldBeGenerated()) { JsStatement statement = generateCallToMain(context, files, mainCallParameters.arguments()); @@ -187,22 +186,18 @@ public final class Translation { statements.add(statement); } } - generateTestCalls(context, files, block, rawStatements); - JsNamer namer = new JsPrettyNamer(); - namer.exec(context.program()); + TestGenerator.generateTestCalls(context, files, rootBlock); + performSimpleNameMangling(context.program()); return context.program(); } - private static void defineModule(@NotNull List statements, - @NotNull TranslationContext context, - @NotNull Config config) { - statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"), - context.program().getStringLiteral(config.getModuleId()), - context.jsScope().declareName("_").makeRef()).makeStmt()); + private static void performSimpleNameMangling(@NotNull JsProgram program) { + JsNamer namer = new JsPrettyNamer(); + namer.exec(program); } @Nullable - private static JsStatement generateCallToMain(@NotNull TranslationContext context, @NotNull List files, + private static JsStatement generateCallToMain(@NotNull TranslationContext context, @NotNull Collection files, @NotNull List arguments) throws MainFunctionNotFoundException { JetNamedFunction mainFunction = getMainFunction(files); if (mainFunction == null) { @@ -228,53 +223,4 @@ public final class Translation { arrayLiteral.getExpressions().addAll(toStringLiteralList(arguments, context.program())); JsAstUtils.setArguments(translatedCall, Collections.singletonList(arrayLiteral)); } - - private static void generateTestCalls(@NotNull TranslationContext context, - @NotNull List files, - @NotNull JsBlock block, - List rawStatements) { - ClassDescriptor lastClassDescriptor = null; - boolean declaredVar = false; - List functions = JetTestFunctionDetector.findTestFunctions(context.bindingContext(), files); - for (JetNamedFunction function : functions) { - FunctionDescriptor functionDescriptor = getFunctionDescriptor(context.bindingContext(), function); - String funName = functionDescriptor.getName().getName(); - DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration(); - if (containingDeclaration instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - String className = getQualifiedName(classDescriptor); - if (lastClassDescriptor != classDescriptor) { - lastClassDescriptor = classDescriptor; - String prefix = ""; - if (!declaredVar) { - prefix = "var "; - declaredVar = true; - } - rawStatements.add(prefix + "_testCase = new Kotlin.main." + className + "();"); - } - rawStatements.add("QUnit.test( \"" + className + "." + funName + "()\" , function() {"); - //rawStatements.add(" expect(0);"); - rawStatements.add(" _testCase." + funName + "();"); - } else { - rawStatements.add("QUnit.test( \"" + funName + "()\", function() {"); - //rawStatements.add(" expect(0);"); - rawStatements.add(" " + funName + "();"); - } - rawStatements.add("});"); - } - } - - public static String getQualifiedName(ClassDescriptor classDescriptor) { - List parts = new ArrayList(); - DeclarationDescriptor current = classDescriptor; - while (current != null) { - String name = current.getName().getName(); - if (name.startsWith("<")) break; - parts.add(name); - current = current.getContainingDeclaration(); - } - Collections.reverse(parts); - return StringUtil.join(parts, "."); - } - } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java b/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java new file mode 100644 index 00000000000..f2bb3a18c79 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/test/TestGenerator.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.test; + +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.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.k2js.translate.context.TranslationContext; +import org.jetbrains.k2js.translate.general.JetTestFunctionDetector; +import org.jetbrains.k2js.translate.reference.CallBuilder; +import org.jetbrains.k2js.translate.reference.ReferenceTranslator; +import org.jetbrains.k2js.translate.utils.JsDescriptorUtils; + +import java.util.Collection; +import java.util.List; + +import static com.google.dart.compiler.util.AstUtil.newBlock; + +/** + * @author Pavel Talanov + */ +public final class TestGenerator { + private TestGenerator() { + } + + public static void generateTestCalls(@NotNull TranslationContext context, + @NotNull Collection files, + @NotNull JsBlock block) { + List functionDescriptors = JetTestFunctionDetector.getTestFunctionDescriptors(context.bindingContext(), files); + doGenerateTestCalls(functionDescriptors, block, context); + } + + private static void doGenerateTestCalls(@NotNull List functionDescriptors, + @NotNull JsBlock block, + @NotNull TranslationContext context) { + for (FunctionDescriptor functionDescriptor : functionDescriptors) { + ClassDescriptor classDescriptor = JsDescriptorUtils.getContainingClass(functionDescriptor); + if (classDescriptor == null) { + return; + } + JsExpression expression = ReferenceTranslator.translateAsFQReference(classDescriptor, context); + JsNew constructClassExpr = new JsNew(expression); + JsExpression functionToTestCall = + CallBuilder.build(context).descriptor(functionDescriptor).receiver(constructClassExpr).translate(); + JsNameRef qUnitTestFunRef = AstUtil.newQualifiedNameRef("QUnit.test"); + JsFunction functionToTest = new JsFunction(context.jsScope()); + functionToTest.setBody(newBlock(functionToTestCall.makeStmt())); + String testName = classDescriptor.getName() + "." + functionDescriptor.getName(); + block.getStatements() + .add(AstUtil.newInvocation(qUnitTestFunRef, context.program().getStringLiteral(testName), functionToTest) + .makeStmt()); + } + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index 30a5d686e18..dbebc88acaf 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -255,4 +255,11 @@ public final class TranslationUtils { public static boolean isNullLiteral(@NotNull TranslationContext context, @NotNull JsExpression expression) { return expression.equals(context.program().getNullLiteral()); } + + public static void defineModule(@NotNull TranslationContext context, @NotNull List statements, + String moduleId) { + statements.add(AstUtil.newInvocation(context.namer().kotlin("defineModule"), + context.program().getStringLiteral(moduleId), + context.jsScope().declareName("_").makeRef()).makeStmt()); + } }