[JS IR BE] support more constructions:

* generate declaration for top level properties
* basic support for calls
* break
* continue
* throw
* generate declaration for local vals and vars
This commit is contained in:
Zalim Bashorov
2018-03-19 17:06:22 +03:00
parent 560e35174b
commit 68457a55a8
9 changed files with 124 additions and 63 deletions
@@ -6,7 +6,7 @@
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.backend.js.utils.TODO
import org.jetbrains.kotlin.ir.declarations.IrTypeAlias
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.js.backend.ast.JsEmpty
@@ -5,10 +5,15 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.js.backend.ast.*
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, Nothing?> {
override fun visitProperty(declaration: IrProperty, data: Nothing?): JsStatement {
return jsVar(declaration.name, declaration.backingField?.initializer?.expression)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Nothing?): JsStatement {
return JsExpressionStatement(transformIrFunctionToJsFunction(declaration))
}
@@ -16,9 +21,9 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
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")
val function = JsFunction(JsFunctionScope(dummyScope, "scope for $funName"), body, "function $funName")
function.name = JsDynamicScope.declareName(funName)
function.name = declaration.name.toJsName()
fun JsFunction.addParameter(parameterName: String) {
val parameter = function.scope.declareName(parameterName)
@@ -5,12 +5,60 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
import org.jetbrains.kotlin.ir.backend.js.utils.parameterCount
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.js.backend.ast.JsExpression
import org.jetbrains.kotlin.js.backend.ast.JsStringLiteral
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.js.backend.ast.*
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, Nothing?> {
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): JsExpression {
return body.expression.accept(this, data)
}
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): JsExpression {
// TODO: support all cases
return JsStringLiteral(expression.value.toString())
}
override fun visitCall(expression: IrCall, data: Nothing?): JsExpression {
// TODO rewrite more accurately, right now it just copy-pasted and adopted from old version
// TODO support:
// * ir intrinsics
// * js be intrinsics
// * js function
// * getters and setters
// * binary and unary operations
val symbol = expression.symbol
val dispatchReceiver = expression.dispatchReceiver?.accept(this, data)
val extensionReceiver = expression.extensionReceiver?.accept(this, data)
// TODO sanitize name
val symbolName = (symbol.owner as IrSimpleFunction).name.asString()
val ref = if (dispatchReceiver != null) JsNameRef(symbolName, dispatchReceiver) else JsNameRef(symbolName)
val arguments =
// TODO mapTo?
(0 until expression.symbol.parameterCount).map {
val argument = expression.getValueArgument(it)
if (argument != null) {
argument.accept(this, data)
} else {
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
}
}
if (symbol is IrConstructorSymbol && symbol.isPrimary) {
return JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
}
return JsInvocation(ref, extensionReceiver?.let { listOf(extensionReceiver) + arguments } ?: arguments)
}
}
@@ -5,13 +5,9 @@
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
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.js.backend.ast.*
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, Nothing?> {
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): JsStatement {
@@ -22,7 +18,23 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
return JsExpressionStatement(expression.accept(IrElementToJsExpressionTransformer(), data))
}
override fun visitBreak(jump: IrBreak, data: Nothing?): JsStatement {
return JsBreak(jump.label?.let(::JsNameRef))
}
override fun visitContinue(jump: IrContinue, data: Nothing?): JsStatement {
return JsContinue(jump.label?.let(::JsNameRef))
}
override fun visitReturn(expression: IrReturn, data: Nothing?): JsStatement {
return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), null))
return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), data))
}
override fun visitThrow(expression: IrThrow, data: Nothing?): JsStatement {
return JsThrow(expression.value.accept(IrElementToJsExpressionTransformer(), data))
}
override fun visitVariable(declaration: IrVariable, data: Nothing?): JsStatement {
return jsVar(declaration.name, declaration.initializer)
}
}
@@ -0,0 +1,23 @@
/*
* 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.IrExpression
import org.jetbrains.kotlin.js.backend.ast.JsDynamicScope
import org.jetbrains.kotlin.js.backend.ast.JsVars
import org.jetbrains.kotlin.name.Name
// TODO don't use JsDynamicScope
val dummyScope = JsDynamicScope
fun Name.toJsName() =
// TODO sanitize
dummyScope.declareName(asString())
fun jsVar(name: Name, initializer: IrExpression?): JsVars {
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), null)
return JsVars(JsVars.JsVar(name.toJsName(), jsInitializer))
}
@@ -0,0 +1,13 @@
/*
* 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.utils
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
val IrFunctionSymbol.parameterCount get() = descriptor.valueParameters.size
val IrConstructorSymbol.isPrimary get() = descriptor.isPrimary
@@ -3,7 +3,7 @@
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.IrElement
@@ -9,5 +9,9 @@ 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/deeplyNestedPackage.kt"
"js/js.translator/testData/box/package/deeplyNestedPackage.kt",
"js/js.translator/testData/box/package/deeplyNestedPackageFunctionCalled.kt",
"js/js.translator/testData/box/multiPackage/nestedPackageFunctionCalledFromOtherPackage.kt",
"js/js.translator/testData/box/expression/identifierClash/useVariableOfNameOfFunction.kt",
"js/js.translator/testData/box/expression/stringClass/stringConstant.kt"
).map { File(it) }
@@ -7383,18 +7383,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
@TestMetadata("useVariableOfNameOfFunction.kt")
public void testUseVariableOfNameOfFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/identifierClash/useVariableOfNameOfFunction.kt");
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
doTest(fileName);
return;
}
try {
doTest(fileName);
}
catch (Throwable ignore) {
ignore.printStackTrace();
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
doTest(fileName);
}
}
@@ -8618,18 +8607,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
@TestMetadata("stringConstant.kt")
public void testStringConstant() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/expression/stringClass/stringConstant.kt");
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
doTest(fileName);
return;
}
try {
doTest(fileName);
}
catch (Throwable ignore) {
ignore.printStackTrace();
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
doTest(fileName);
}
@TestMetadata("stringInTemplate.kt")
@@ -16617,18 +16595,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
@TestMetadata("nestedPackageFunctionCalledFromOtherPackage.kt")
public void testNestedPackageFunctionCalledFromOtherPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/multiPackage/nestedPackageFunctionCalledFromOtherPackage.kt");
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
doTest(fileName);
return;
}
try {
doTest(fileName);
}
catch (Throwable ignore) {
ignore.printStackTrace();
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
doTest(fileName);
}
@TestMetadata("packageVariableVisibleFromOtherPackage.kt")
@@ -19177,18 +19144,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
@TestMetadata("deeplyNestedPackageFunctionCalled.kt")
public void testDeeplyNestedPackageFunctionCalled() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/package/deeplyNestedPackageFunctionCalled.kt");
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
doTest(fileName);
return;
}
try {
doTest(fileName);
}
catch (Throwable ignore) {
ignore.printStackTrace();
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
doTest(fileName);
}
@TestMetadata("initializersOfNestedPackagesExecute.kt")