From e0a070ff3556dbcba2510b190d591facc8097926 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Wed, 14 Mar 2018 20:24:02 +0300 Subject: [PATCH] [JS IR BE] basic compiler --- .../ir/backend/js/JsIrBackendContext.kt | 8 +++++ .../kotlin/ir/backend/js/compiler.kt | 29 +++++++++++---- .../irToJs/IrDeclarationToJsTransformer.kt | 36 +++++++++++++++++++ .../IrElementToJsExpressionTransformer.kt | 16 +++++++++ .../irToJs/IrElementToJsNodeTransformer.kt.kt | 24 +++++++++++++ .../IrElementToJsStatementTransformer.kt | 28 +++++++++++++++ .../transformers/irToJs/IrFileTransformer.kt | 22 ++++++++++++ .../irToJs/IrModuleTransformer.kt | 22 ++++++++++++ .../jetbrains/kotlin/ir/backend/js/utils.kt | 10 ++++++ .../kotlin/test/jsIrBackendTestWhitelist.kt | 3 +- .../kotlin/js/test/BasicIrBoxTest.kt | 12 +++++-- .../test/semantics/IrBoxJsTestGenerated.java | 8 +---- 12 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsNodeTransformer.kt.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrFileTransformer.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleTransformer.kt create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt new file mode 100644 index 00000000000..275d6998939 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js + +class JsIrBackendContext \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 582f301d563..60d1a5ebdc8 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -1,16 +1,33 @@ /* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.ir.backend.js +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleTransformer +import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator -// Dummy compile function to work on the test infrastructure fun compile( - files: List + project: Project, + files: List, + configuration: CompilerConfiguration, + export: FqName ): String { - if (files.none { it.name == "nestedPackage.kt" }) return "" - return "function box() { return \"OK\"; }" -} \ No newline at end of file + val analysisResult = TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, emptyList(), emptyList()) + ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() + + TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) + + val moduleFragment = Psi2IrTranslator().generateModule(analysisResult.moduleDescriptor, files, analysisResult.bindingContext) + + val program = moduleFragment.accept(IrModuleTransformer(), null) + + return program.toString() +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt new file mode 100644 index 00000000000..1b8371e3a4b --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.js.backend.ast.* + +class IrDeclarationToJsTransformer : IrElementToJsNodeTransformer { + override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Nothing?): JsStatement { + return JsExpressionStatement(transformIrFunctionToJsFunction(declaration)) + } + + private fun transformIrFunctionToJsFunction(declaration: IrSimpleFunction): JsFunction { + val funName = declaration.name.asString() + val body = declaration.body?.accept(IrElementToJsStatementTransformer(), null) as? JsBlock ?: JsBlock() + val function = JsFunction(JsFunctionScope(JsDynamicScope, "scope for $funName"), body, "function $funName") + + function.name = JsDynamicScope.declareName(funName) + + fun JsFunction.addParameter(parameterName: String) { + val parameter = function.scope.declareName(parameterName) + parameters.add(JsParameter(parameter)) + } + + declaration.extensionReceiverParameter?.let { function.addParameter("\$receiver") } + declaration.valueParameters.forEach { + function.addParameter(it.name.asString()) + } + + return function + } + +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt new file mode 100644 index 00000000000..8880b7c4d49 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsExpressionTransformer.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.js.backend.ast.JsExpression +import org.jetbrains.kotlin.js.backend.ast.JsStringLiteral + +class IrElementToJsExpressionTransformer : IrElementToJsNodeTransformer { + override fun visitConst(expression: IrConst, data: Nothing?): JsExpression { + return JsStringLiteral(expression.value.toString()) + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsNodeTransformer.kt.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsNodeTransformer.kt.kt new file mode 100644 index 00000000000..c8404da2ad4 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsNodeTransformer.kt.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.backend.js.TODO +import org.jetbrains.kotlin.ir.declarations.IrTypeAlias +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.js.backend.ast.JsEmpty +import org.jetbrains.kotlin.js.backend.ast.JsNode + +interface IrElementToJsNodeTransformer : IrElementVisitor { + override fun visitElement(element: IrElement, data: D): R { + TODO(element) + } + + override fun visitTypeAlias(declaration: IrTypeAlias, data: D): R { + @Suppress("UNCHECKED_CAST") + return JsEmpty as R + } +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt new file mode 100644 index 00000000000..e30d05bbbc7 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrElementToJsStatementTransformer.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.expressions.IrBlockBody +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrReturn +import org.jetbrains.kotlin.js.backend.ast.JsBlock +import org.jetbrains.kotlin.js.backend.ast.JsExpressionStatement +import org.jetbrains.kotlin.js.backend.ast.JsReturn +import org.jetbrains.kotlin.js.backend.ast.JsStatement + +class IrElementToJsStatementTransformer : IrElementToJsNodeTransformer { + override fun visitBlockBody(body: IrBlockBody, data: Nothing?): JsStatement { + return JsBlock(body.statements.map { it.accept(this, data) }) + } + + override fun visitExpression(expression: IrExpression, data: Nothing?): JsStatement { + return JsExpressionStatement(expression.accept(IrElementToJsExpressionTransformer(), data)) + } + + override fun visitReturn(expression: IrReturn, data: Nothing?): JsStatement { + return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), null)) + } +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrFileTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrFileTransformer.kt new file mode 100644 index 00000000000..a13de2afd5c --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrFileTransformer.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.js.backend.ast.JsBlock +import org.jetbrains.kotlin.js.backend.ast.JsStatement + +class IrFileTransformer : IrElementToJsNodeTransformer { + override fun visitFile(declaration: IrFile, data: Nothing?): JsStatement { + val block = JsBlock() + + declaration.declarations.forEach { + block.statements.add(it.accept(IrDeclarationToJsTransformer(), null)) + } + + return block + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleTransformer.kt new file mode 100644 index 00000000000..639c22f6d9b --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleTransformer.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs + +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.js.backend.ast.JsNode +import org.jetbrains.kotlin.js.backend.ast.JsProgram + +class IrModuleTransformer : IrElementToJsNodeTransformer { + override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode { + val program = JsProgram() + + declaration.files.forEach { + program.globalBlock.statements.add(it.accept(IrFileTransformer(), null)) + } + + return program + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils.kt new file mode 100644 index 00000000000..f7790069981 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js + +import org.jetbrains.kotlin.ir.IrElement + +fun TODO(element: IrElement): Nothing = TODO(element::class.java.simpleName + " is not supported yet here") \ No newline at end of file diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/jsIrBackendTestWhitelist.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/jsIrBackendTestWhitelist.kt index 0726287c169..15b2b7fba86 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/jsIrBackendTestWhitelist.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/jsIrBackendTestWhitelist.kt @@ -8,5 +8,6 @@ package org.jetbrains.kotlin.test import java.io.File val JS_IR_BACKEND_TEST_WHITELIST = listOf( - "js/js.translator/testData/box/package/nestedPackage.kt" + "js/js.translator/testData/box/package/nestedPackage.kt", + "js/js.translator/testData/box/package/deeplyNestedPackage.kt" ).map { File(it) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt index c4b651b47ef..3e3a2aca660 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.js.config.JsConfig import org.jetbrains.kotlin.js.facade.MainCallParameters import org.jetbrains.kotlin.js.facade.TranslationUnit +import org.jetbrains.kotlin.name.FqName import java.io.File abstract class BasicIrBoxTest( @@ -33,7 +34,14 @@ abstract class BasicIrBoxTest( testPackage: String?, testFunction: String ) { - val code = compile(units.map { (it as TranslationUnit.SourceFile).file }) + val code = compile( + config.project, + units.map { (it as TranslationUnit.SourceFile).file } + // TODO: temporary ignore _commonFiles/asserts.kt since it depends on stdlib but we don't have any library support in JS IR BE yet + // and probably it will be better to avoid using stdlib in testData as much as possible. + .filter { !it.virtualFilePath.endsWith("js/js.translator/testData/_commonFiles/asserts.kt") }, + config.configuration, + FqName((testPackage?.let { it + "." } ?: "") + testFunction)) outputFile.parentFile.mkdirs() outputFile.writeText(code) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index d242704d572..6ac3ffd3b11 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -13731,13 +13731,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { @TestMetadata("deeplyNestedPackage.kt") public void testDeeplyNestedPackage() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/package/deeplyNestedPackage.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to white list for that."); + doTest(fileName); } @TestMetadata("deeplyNestedPackageFunctionCalled.kt")