Implement basic IR -> JS class translation
This commit is contained in:
@@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
+14
-23
@@ -5,37 +5,28 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, Nothing?> {
|
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
override fun visitProperty(declaration: IrProperty, data: Nothing?): JsStatement {
|
override fun visitProperty(declaration: IrProperty, context: JsGenerationContext): JsStatement {
|
||||||
return jsVar(declaration.name, declaration.backingField?.initializer?.expression)
|
return jsVar(declaration.name, declaration.backingField?.initializer?.expression, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Nothing?): JsStatement {
|
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsStatement {
|
||||||
return JsExpressionStatement(transformIrFunctionToJsFunction(declaration))
|
return declaration.accept(IrFunctionToJsTransformer(), context).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformIrFunctionToJsFunction(declaration: IrSimpleFunction): JsFunction {
|
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsStatement {
|
||||||
val funName = declaration.name.asString()
|
return declaration.accept(IrFunctionToJsTransformer(), context).makeStmt()
|
||||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), null) as? JsBlock ?: JsBlock()
|
|
||||||
val function = JsFunction(JsFunctionScope(dummyScope, "scope for $funName"), body, "function $funName")
|
|
||||||
|
|
||||||
function.name = declaration.name.toJsName()
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass, context: JsGenerationContext): JsStatement {
|
||||||
|
return JsClassGenerator(declaration, context).generate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-38
@@ -5,21 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.name
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.parameterCount
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, Nothing?> {
|
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
||||||
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): JsExpression {
|
override fun visitExpressionBody(body: IrExpressionBody, context: JsGenerationContext): JsExpression {
|
||||||
return body.expression.accept(this, data)
|
return body.expression.accept(this, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): JsExpression {
|
override fun <T> visitConst(expression: IrConst<T>, context: JsGenerationContext): JsExpression {
|
||||||
val kind = expression.kind
|
val kind = expression.kind
|
||||||
return when (kind) {
|
return when (kind) {
|
||||||
is IrConstKind.String -> JsStringLiteral(kind.valueOf(expression))
|
is IrConstKind.String -> JsStringLiteral(kind.valueOf(expression))
|
||||||
@@ -29,34 +27,57 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
|
is IrConstKind.Short -> JsIntLiteral(kind.valueOf(expression).toInt())
|
||||||
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
|
is IrConstKind.Int -> JsIntLiteral(kind.valueOf(expression))
|
||||||
is IrConstKind.Long,
|
is IrConstKind.Long,
|
||||||
is IrConstKind.Char -> super.visitConst(expression, data)
|
is IrConstKind.Char -> super.visitConst(expression, context)
|
||||||
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
|
is IrConstKind.Float -> JsDoubleLiteral(kind.valueOf(expression).toDouble())
|
||||||
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
|
is IrConstKind.Double -> JsDoubleLiteral(kind.valueOf(expression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): JsExpression {
|
override fun visitStringConcatenation(expression: IrStringConcatenation, context: JsGenerationContext): JsExpression {
|
||||||
// TODO revisit
|
// TODO revisit
|
||||||
return expression.arguments.fold<IrExpression, JsExpression>(JsStringLiteral("")) { jsExpr, irExpr ->
|
return expression.arguments.fold<IrExpression, JsExpression>(JsStringLiteral("")) { jsExpr, irExpr ->
|
||||||
JsBinaryOperation(
|
JsBinaryOperation(
|
||||||
JsBinaryOperator.ADD,
|
JsBinaryOperator.ADD,
|
||||||
jsExpr,
|
jsExpr,
|
||||||
irExpr.accept(this, data)
|
irExpr.accept(this, context)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue, data: Nothing?): JsExpression {
|
override fun visitGetField(expression: IrGetField, context: JsGenerationContext): JsExpression {
|
||||||
return JsNameRef(expression.symbol.name.toJsName())
|
return JsNameRef(expression.symbol.name.asString(), expression.receiver?.accept(this, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): JsExpression {
|
override fun visitGetValue(expression: IrGetValue, context: JsGenerationContext): JsExpression {
|
||||||
|
|
||||||
|
return if (expression.symbol.isSpecial) {
|
||||||
|
context.getSpecialRefForName(expression.symbol.name)
|
||||||
|
} else {
|
||||||
|
JsNameRef(context.getNameForSymbol(expression.symbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField, context: JsGenerationContext): JsExpression {
|
||||||
|
val dest = JsNameRef(expression.symbol.name.asString(), expression.receiver?.accept(this, context))
|
||||||
|
val source = expression.value.accept(this, context)
|
||||||
|
return jsAssignment(dest, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetVariable(expression: IrSetVariable, context: JsGenerationContext): JsExpression {
|
||||||
val ref = JsNameRef(expression.symbol.name.toJsName())
|
val ref = JsNameRef(expression.symbol.name.toJsName())
|
||||||
val value = expression.value.accept(this, data)
|
val value = expression.value.accept(this, context)
|
||||||
return JsBinaryOperation(JsBinaryOperator.ASG, ref, value)
|
return JsBinaryOperation(JsBinaryOperator.ASG, ref, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, data: Nothing?): JsExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
||||||
|
val classNameRef = expression.symbol.owner.descriptor.constructedClass.name.toJsName().makeRef()
|
||||||
|
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
|
||||||
|
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
||||||
|
return JsInvocation(callFuncRef, listOf(JsThisRef()) + arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
|
||||||
// TODO rewrite more accurately, right now it just copy-pasted and adopted from old version
|
// TODO rewrite more accurately, right now it just copy-pasted and adopted from old version
|
||||||
// TODO support:
|
// TODO support:
|
||||||
// * ir intrinsics
|
// * ir intrinsics
|
||||||
@@ -67,34 +88,24 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
|
|
||||||
val symbol = expression.symbol
|
val symbol = expression.symbol
|
||||||
|
|
||||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, data)
|
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
||||||
val extensionReceiver = expression.extensionReceiver?.accept(this, data)
|
val extensionReceiver = expression.extensionReceiver?.accept(this, context)
|
||||||
|
|
||||||
// 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) {
|
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
||||||
return JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
|
||||||
|
return if (symbol is IrConstructorSymbol && symbol.isPrimary) {
|
||||||
|
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
||||||
|
} else {
|
||||||
|
// TODO sanitize name
|
||||||
|
val symbolName = context.getNameForSymbol(symbol)
|
||||||
|
val ref = if (dispatchReceiver != null) JsNameRef(symbolName, dispatchReceiver) else JsNameRef(symbolName)
|
||||||
|
JsInvocation(ref, extensionReceiver?.let { listOf(extensionReceiver) + arguments } ?: arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsInvocation(ref, extensionReceiver?.let { listOf(extensionReceiver) + arguments } ?: arguments)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: Nothing?): JsExpression {
|
override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsExpression {
|
||||||
// TODO check when w/o else branch and empty when
|
// TODO check when w/o else branch and empty when
|
||||||
return expression.toJsNode(this, data, ::JsConditional)!!
|
return expression.toJsNode(this, context, ::JsConditional)!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+38
-23
@@ -5,59 +5,74 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, Nothing?> {
|
class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): JsStatement {
|
override fun visitBlockBody(body: IrBlockBody, context: JsGenerationContext): JsStatement {
|
||||||
return JsBlock(body.statements.map { it.accept(this, data) })
|
return JsBlock(body.statements.map { it.accept(this, context) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(expression: IrBlock, data: Nothing?): JsBlock {
|
override fun visitBlock(expression: IrBlock, context: JsGenerationContext): JsBlock {
|
||||||
return JsBlock(expression.statements.map { it.accept(this, data) })
|
return JsBlock(expression.statements.map { it.accept(this, context) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitComposite(expression: IrComposite, data: Nothing?): JsStatement {
|
override fun visitComposite(expression: IrComposite, context: JsGenerationContext): JsStatement {
|
||||||
// TODO introduce JsCompositeBlock?
|
// TODO introduce JsCompositeBlock?
|
||||||
return JsBlock(expression.statements.map { it.accept(this, data) })
|
return JsBlock(expression.statements.map { it.accept(this, context) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitExpression(expression: IrExpression, data: Nothing?): JsStatement {
|
override fun visitExpression(expression: IrExpression, context: JsGenerationContext): JsStatement {
|
||||||
return JsExpressionStatement(expression.accept(IrElementToJsExpressionTransformer(), data))
|
return JsExpressionStatement(expression.accept(IrElementToJsExpressionTransformer(), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBreak(jump: IrBreak, data: Nothing?): JsStatement {
|
override fun visitBreak(jump: IrBreak, context: JsGenerationContext): JsStatement {
|
||||||
return JsBreak(jump.label?.let(::JsNameRef))
|
return JsBreak(jump.label?.let(::JsNameRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitContinue(jump: IrContinue, data: Nothing?): JsStatement {
|
override fun visitContinue(jump: IrContinue, context: JsGenerationContext): JsStatement {
|
||||||
return JsContinue(jump.label?.let(::JsNameRef))
|
return JsContinue(jump.label?.let(::JsNameRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturn(expression: IrReturn, data: Nothing?): JsStatement {
|
override fun visitReturn(expression: IrReturn, context: JsGenerationContext): JsStatement {
|
||||||
return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), data))
|
return JsReturn(expression.value.accept(IrElementToJsExpressionTransformer(), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitThrow(expression: IrThrow, data: Nothing?): JsStatement {
|
override fun visitThrow(expression: IrThrow, context: JsGenerationContext): JsStatement {
|
||||||
return JsThrow(expression.value.accept(IrElementToJsExpressionTransformer(), data))
|
return JsThrow(expression.value.accept(IrElementToJsExpressionTransformer(), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVariable(declaration: IrVariable, data: Nothing?): JsStatement {
|
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||||
return jsVar(declaration.name, declaration.initializer)
|
return jsVar(declaration.name, declaration.initializer, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhen(expression: IrWhen, data: Nothing?): JsStatement {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsStatement {
|
||||||
return expression.toJsNode(this, data, ::JsIf) ?: JsEmpty
|
if (KotlinBuiltIns.isAny(expression.symbol.constructedClass)) {
|
||||||
|
return JsEmpty
|
||||||
|
}
|
||||||
|
return expression.accept(IrElementToJsExpressionTransformer(), context).makeStmt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): JsStatement {
|
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, context: JsGenerationContext): JsStatement {
|
||||||
|
|
||||||
|
// TODO: implement
|
||||||
|
return JsEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsStatement {
|
||||||
|
return expression.toJsNode(this, context, ::JsIf) ?: JsEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhileLoop(loop: IrWhileLoop, context: JsGenerationContext): JsStatement {
|
||||||
//TODO what if body null?
|
//TODO what if body null?
|
||||||
return JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), data), loop.body?.accept(this, data))
|
return JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): JsStatement {
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, context: JsGenerationContext): JsStatement {
|
||||||
//TODO what if body null?
|
//TODO what if body null?
|
||||||
return JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), data), loop.body?.accept(this, data))
|
return JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -5,16 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
import org.jetbrains.kotlin.ir.declarations.name
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsDeclarationScope
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||||
|
|
||||||
class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, Nothing?> {
|
class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
override fun visitFile(declaration: IrFile, data: Nothing?): JsStatement {
|
override fun visitFile(declaration: IrFile, context: JsGenerationContext): JsStatement {
|
||||||
val block = JsBlock()
|
val fileContext = context.newDeclaration(JsDeclarationScope(context.currentScope, "scope for file ${declaration.name}"))
|
||||||
|
val block = fileContext.currentBlock
|
||||||
|
|
||||||
declaration.declarations.forEach {
|
declaration.declarations.forEach {
|
||||||
block.statements.add(it.accept(IrDeclarationToJsTransformer(), null))
|
block.statements.add(it.accept(IrDeclarationToJsTransformer(), fileContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
return block
|
return block
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.backend.js.utils.JsGenerationContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.constructedClassName
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsFunction
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||||
|
|
||||||
|
open class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFunction, JsGenerationContext> {
|
||||||
|
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsFunction {
|
||||||
|
return translateFunction(declaration, declaration.name, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsFunction {
|
||||||
|
assert(declaration.symbol.isPrimary)
|
||||||
|
return translateFunction(declaration, declaration.symbol.constructedClassName, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+4
-1
@@ -5,16 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||||
|
|
||||||
class IrModuleToJsTransformer : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
class IrModuleToJsTransformer : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
||||||
val program = JsProgram()
|
val program = JsProgram()
|
||||||
|
val rootContext = JsGenerationContext(JsRootScope(program))
|
||||||
|
|
||||||
declaration.files.forEach {
|
declaration.files.forEach {
|
||||||
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), null))
|
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
return program
|
return program
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
|
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||||
|
|
||||||
|
private val classNameRef = irClass.name.toJsName().makeRef()
|
||||||
|
private val classPrototypeRef = prototypeOf(classNameRef)
|
||||||
|
private val classBlock = JsBlock()
|
||||||
|
|
||||||
|
fun generate(): JsStatement {
|
||||||
|
|
||||||
|
maybeGeneratePrimaryConstructor()
|
||||||
|
val transformer = IrFunctionToJsTransformer()
|
||||||
|
|
||||||
|
for (declaration in irClass.declarations) {
|
||||||
|
if (declaration is IrConstructor) {
|
||||||
|
classBlock.statements += declaration.accept(transformer, context).makeStmt()
|
||||||
|
classBlock.statements += generateInheritanceCode()
|
||||||
|
} else if (declaration is IrFunction) {
|
||||||
|
if (declaration.symbol.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||||
|
declaration.symbol.modality != Modality.ABSTRACT
|
||||||
|
) {
|
||||||
|
classBlock.statements += declaration.accept(transformer, context).apply { name = null }.let {
|
||||||
|
val memberName = context.getNameForSymbol(declaration.symbol)
|
||||||
|
val memberRef = JsNameRef(memberName, classPrototypeRef)
|
||||||
|
jsAssignment(memberRef, it).makeStmt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classBlock.statements += generateClassMetadata()
|
||||||
|
return classBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeGeneratePrimaryConstructor() {
|
||||||
|
if (!irClass.declarations.any { it is IrConstructor }) {
|
||||||
|
val func = JsFunction(JsFunctionScope(context.currentScope, "Ctor for ${irClass.name}"), JsBlock(), "Ctor for ${irClass.name}")
|
||||||
|
func.name = irClass.name.toJsName()
|
||||||
|
classBlock.statements += func.makeStmt()
|
||||||
|
classBlock.statements += generateInheritanceCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateInheritanceCode(): List<JsStatement> {
|
||||||
|
val baseClass = irClass.superClasses.first { it.kind != ClassKind.INTERFACE }
|
||||||
|
if (baseClass.isAny) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
val createCall = jsAssignment(
|
||||||
|
classPrototypeRef, JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototypeOf(baseClass.owner.name.toJsName().makeRef()))
|
||||||
|
).makeStmt()
|
||||||
|
|
||||||
|
val ctorAssign = jsAssignment(JsNameRef(Namer.CONSTRUCTOR_NAME, classPrototypeRef), classNameRef).makeStmt()
|
||||||
|
|
||||||
|
return listOf(createCall, ctorAssign)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateClassMetadata(): JsStatement {
|
||||||
|
val metadataLiteral = JsObjectLiteral(true)
|
||||||
|
val simpleName = irClass.symbol.name
|
||||||
|
|
||||||
|
if (!simpleName.isSpecial) {
|
||||||
|
val simpleNameProp = JsPropertyInitializer(JsNameRef(Namer.METADATA_SIMPLE_NAME), JsStringLiteral(simpleName.identifier))
|
||||||
|
metadataLiteral.propertyInitializers += simpleNameProp
|
||||||
|
}
|
||||||
|
|
||||||
|
metadataLiteral.propertyInitializers += generateSuperClasses()
|
||||||
|
return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), metadataLiteral).makeStmt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateSuperClasses(): JsPropertyInitializer = JsPropertyInitializer(
|
||||||
|
JsNameRef(Namer.METADATA_INTERFACES),
|
||||||
|
JsArrayLiteral(irClass.superClasses.filter { it.kind == ClassKind.INTERFACE }.map { JsNameRef(it.owner.name.toJsName()) })
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
+50
-11
@@ -5,14 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBranch
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrElseBranch
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsDynamicScope
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsVars
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
// TODO don't use JsDynamicScope
|
// TODO don't use JsDynamicScope
|
||||||
@@ -22,12 +19,12 @@ fun Name.toJsName() =
|
|||||||
// TODO sanitize
|
// TODO sanitize
|
||||||
dummyScope.declareName(asString())
|
dummyScope.declareName(asString())
|
||||||
|
|
||||||
fun jsVar(name: Name, initializer: IrExpression?): JsVars {
|
fun jsVar(name: Name, initializer: IrExpression?, context: JsGenerationContext): JsVars {
|
||||||
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), null)
|
val jsInitializer = initializer?.accept(IrElementToJsExpressionTransformer(), context)
|
||||||
return JsVars(JsVars.JsVar(name.toJsName(), jsInitializer))
|
return JsVars(JsVars.JsVar(name.toJsName(), jsInitializer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : JsNode, D : Nothing?> IrWhen.toJsNode(tr: BaseIrElementToJsNodeTransformer<T, D>, data: D, node: (JsExpression, T, T?) -> T): T? =
|
fun <T : JsNode, D : JsGenerationContext> IrWhen.toJsNode(tr: BaseIrElementToJsNodeTransformer<T, D>, data: D, node: (JsExpression, T, T?) -> T): T? =
|
||||||
branches.foldRight<IrBranch, T?>(null) { br, n ->
|
branches.foldRight<IrBranch, T?>(null) { br, n ->
|
||||||
val body = br.result.accept(tr, data)
|
val body = br.result.accept(tr, data)
|
||||||
if (br is IrElseBranch) body
|
if (br is IrElseBranch) body
|
||||||
@@ -36,3 +33,45 @@ fun <T : JsNode, D : Nothing?> IrWhen.toJsNode(tr: BaseIrElementToJsNodeTransfor
|
|||||||
node(condition, body, n)
|
node(condition, body, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun jsAssignment(left: JsExpression, right: JsExpression) = JsBinaryOperation(JsBinaryOperator.ASG, left, right)
|
||||||
|
|
||||||
|
fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, classNameRef)
|
||||||
|
|
||||||
|
fun translateFunction(declaration: IrFunction, name: Name?, context: JsGenerationContext): JsFunction {
|
||||||
|
val functionScope = JsFunctionScope(context.currentScope, "scope for ${name ?: "annon"}")
|
||||||
|
val functionContext = context.newDeclaration(functionScope)
|
||||||
|
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||||
|
val function = JsFunction(functionScope, body, "member function ${name ?: "annon"}")
|
||||||
|
|
||||||
|
function.name = name?.toJsName()
|
||||||
|
|
||||||
|
fun JsFunction.addParameter(parameterName: String) {
|
||||||
|
val parameter = function.scope.declareName(parameterName)
|
||||||
|
parameters.add(JsParameter(parameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration.extensionReceiverParameter?.let { function.addParameter("\$receiver") }
|
||||||
|
declaration.valueParameters.forEach {
|
||||||
|
if (it.name.isSpecial) {
|
||||||
|
function.addParameter(context.staticContext.getSpecialNameString(it.name.asString()))
|
||||||
|
} else {
|
||||||
|
function.addParameter(it.name.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function
|
||||||
|
}
|
||||||
|
|
||||||
|
fun translateCallArguments(
|
||||||
|
expression: IrMemberAccessExpression,
|
||||||
|
parameterCount: Int,
|
||||||
|
context: JsGenerationContext
|
||||||
|
): List<JsExpression> {
|
||||||
|
val transformer = IrElementToJsExpressionTransformer()
|
||||||
|
// TODO: map to?
|
||||||
|
return (0 until parameterCount).map {
|
||||||
|
val argument = expression.getValueArgument(it)
|
||||||
|
argument?.accept(transformer, context) ?: JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsExpressionTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsStatementTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.toJsName
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class JsGenerationContext {
|
||||||
|
fun newDeclaration(scope: JsScope): JsGenerationContext {
|
||||||
|
return JsGenerationContext(this, JsBlock(), scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentBlock: JsBlock
|
||||||
|
val currentScope: JsScope
|
||||||
|
val parent: JsGenerationContext?
|
||||||
|
val staticContext: JsStaticContext
|
||||||
|
private val program: JsProgram
|
||||||
|
|
||||||
|
constructor(rootScope: JsRootScope) {
|
||||||
|
|
||||||
|
this.parent = null
|
||||||
|
this.program = rootScope.program
|
||||||
|
this.staticContext = JsStaticContext(rootScope, program.globalBlock, SimpleNameGenerator())
|
||||||
|
this.currentScope = rootScope
|
||||||
|
this.currentBlock = program.globalBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope) {
|
||||||
|
this.parent = parent
|
||||||
|
this.program = parent.program
|
||||||
|
this.staticContext = parent.staticContext
|
||||||
|
this.currentBlock = block
|
||||||
|
this.currentScope = scope
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol)
|
||||||
|
fun getSpecialRefForName(name: Name): JsExpression = staticContext.getSpecialRefForName(name)
|
||||||
|
}
|
||||||
+23
@@ -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.utils
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
|
||||||
|
class JsStaticContext(
|
||||||
|
private val rootScope: JsRootScope,
|
||||||
|
private val globalBlock: JsGlobalBlock,
|
||||||
|
private val nameGenerator: NameGenerator
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
|
||||||
|
fun getSpecialRefForName(name: Name): JsExpression = nameGenerator.getSpecialRefForName(name)
|
||||||
|
fun getSpecialNameString(specNameString: String): String = nameGenerator.getSpecialNameString(specNameString)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
interface NameGenerator {
|
||||||
|
fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName
|
||||||
|
|
||||||
|
fun getSpecialRefForName(name: Name): JsExpression
|
||||||
|
fun getSpecialNameString(specNameString: String): String
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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.idea.KotlinLanguage
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||||
|
|
||||||
|
object Namer {
|
||||||
|
val KOTLIN_NAME = KotlinLanguage.NAME
|
||||||
|
val KOTLIN_LOWER_NAME = KOTLIN_NAME.toLowerCase()
|
||||||
|
|
||||||
|
// val EQUALS_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getAny(), "equals")
|
||||||
|
// val COMPARE_TO_METHOD_NAME = getStableMangledNameForDescriptor(JsPlatform.INSTANCE.getBuiltIns().getComparable(), "compareTo")
|
||||||
|
val LONG_FROM_NUMBER = "fromNumber"
|
||||||
|
val LONG_TO_NUMBER = "toNumber"
|
||||||
|
val LONG_FROM_INT = "fromInt"
|
||||||
|
val LONG_ZERO = "ZERO"
|
||||||
|
val LONG_ONE = "ONE"
|
||||||
|
val LONG_NEG_ONE = "NEG_ONE"
|
||||||
|
val LONG_MAX_VALUE = "MAX_VALUE"
|
||||||
|
val LONG_MIN_VALUE = "MIN_VALUE"
|
||||||
|
val PRIMITIVE_COMPARE_TO = "primitiveCompareTo"
|
||||||
|
val IS_CHAR = "isChar"
|
||||||
|
val IS_NUMBER = "isNumber"
|
||||||
|
val IS_CHAR_SEQUENCE = "isCharSequence"
|
||||||
|
val GET_KCLASS = "getKClass"
|
||||||
|
val GET_KCLASS_FROM_EXPRESSION = "getKClassFromExpression"
|
||||||
|
|
||||||
|
val CALLEE_NAME = "\$fun"
|
||||||
|
|
||||||
|
val CALL_FUNCTION = "call"
|
||||||
|
val APPLY_FUNCTION = "apply"
|
||||||
|
|
||||||
|
val OUTER_FIELD_NAME = "\$outer"
|
||||||
|
|
||||||
|
val DELEGATE = "\$delegate"
|
||||||
|
|
||||||
|
val ROOT_PACKAGE = "_"
|
||||||
|
|
||||||
|
val RECEIVER_PARAMETER_NAME = "\$receiver"
|
||||||
|
val ANOTHER_THIS_PARAMETER_NAME = "$this"
|
||||||
|
|
||||||
|
val THROW_CLASS_CAST_EXCEPTION_FUN_NAME = "throwCCE"
|
||||||
|
val THROW_ILLEGAL_STATE_EXCEPTION_FUN_NAME = "throwISE"
|
||||||
|
val THROW_UNINITIALIZED_PROPERTY_ACCESS_EXCEPTION = "throwUPAE"
|
||||||
|
val NULL_CHECK_INTRINSIC_NAME = "ensureNotNull"
|
||||||
|
val PROTOTYPE_NAME = "prototype"
|
||||||
|
val CONSTRUCTOR_NAME = "constructor"
|
||||||
|
val CAPTURED_VAR_FIELD = "v"
|
||||||
|
|
||||||
|
val IS_ARRAY_FUN_REF = JsNameRef("isArray", "Array")
|
||||||
|
val DEFINE_INLINE_FUNCTION = "defineInlineFunction"
|
||||||
|
val DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "\$default"
|
||||||
|
|
||||||
|
val JS_OBJECT = JsNameRef("Object")
|
||||||
|
val JS_OBJECT_CREATE_FUNCTION = JsNameRef("create", JS_OBJECT)
|
||||||
|
|
||||||
|
val LOCAL_MODULE_PREFIX = "\$module\$"
|
||||||
|
val METADATA = "\$metadata\$"
|
||||||
|
val METADATA_INTERFACES = "interfaces"
|
||||||
|
val METADATA_SIMPLE_NAME = "simpleName"
|
||||||
|
val METADATA_CLASS_KIND = "kind"
|
||||||
|
val CLASS_KIND_ENUM = "Kind"
|
||||||
|
val CLASS_KIND_CLASS = "CLASS"
|
||||||
|
val CLASS_KIND_INTERFACE = "INTERFACE"
|
||||||
|
val CLASS_KIND_OBJECT = "OBJECT"
|
||||||
|
|
||||||
|
val OBJECT_INSTANCE_VAR_SUFFIX = "_instance"
|
||||||
|
val OBJECT_INSTANCE_FUNCTION_SUFFIX = "_getInstance"
|
||||||
|
|
||||||
|
val ENUM_NAME_FIELD = "name\$"
|
||||||
|
val ENUM_ORDINAL_FIELD = "ordinal\$"
|
||||||
|
|
||||||
|
val IMPORTS_FOR_INLINE_PROPERTY = "\$\$importsForInline\$\$"
|
||||||
|
|
||||||
|
val GETTER_PREFIX = "get_"
|
||||||
|
val SETTER_PREFIX = "set_"
|
||||||
|
|
||||||
|
val SETTER_ARGUMENT = "\$setValue"
|
||||||
|
|
||||||
|
val THIS_SPECIAL_NAME = "<this>"
|
||||||
|
val SET_SPECIAL_NAME = "<set-?>"
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class SimpleNameGenerator : NameGenerator {
|
||||||
|
|
||||||
|
private val nameCache = mutableMapOf<DeclarationDescriptor, JsName>()
|
||||||
|
|
||||||
|
override fun getNameForSymbol(symbol: IrSymbol, scope: JsScope): JsName = getNameForDescriptor(symbol.descriptor, scope)
|
||||||
|
|
||||||
|
override fun getSpecialRefForName(name: Name): JsExpression {
|
||||||
|
assert(name.isSpecial)
|
||||||
|
|
||||||
|
val nameString = name.asString()
|
||||||
|
return when (nameString) {
|
||||||
|
Namer.THIS_SPECIAL_NAME -> JsThisRef()
|
||||||
|
else -> JsNameRef(getSpecialNameString(nameString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSpecialNameString(specNameString: String): String = when (specNameString) {
|
||||||
|
Namer.SET_SPECIAL_NAME -> Namer.SETTER_ARGUMENT
|
||||||
|
else -> TODO("for Name ${specNameString}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNameForDescriptor(descriptor: DeclarationDescriptor, scope: JsScope): JsName = nameCache.getOrPut(descriptor, {
|
||||||
|
val nameBuilder = StringBuilder()
|
||||||
|
when (descriptor) {
|
||||||
|
is PropertyAccessorDescriptor -> {
|
||||||
|
when (descriptor) {
|
||||||
|
is PropertyGetterDescriptor -> nameBuilder.append(Namer.GETTER_PREFIX)
|
||||||
|
is PropertySetterDescriptor -> nameBuilder.append(Namer.SETTER_PREFIX)
|
||||||
|
}
|
||||||
|
nameBuilder.append(descriptor.correspondingProperty.name.asString())
|
||||||
|
}
|
||||||
|
is CallableDescriptor -> {
|
||||||
|
nameBuilder.append(descriptor.name.asString())
|
||||||
|
descriptor.typeParameters.forEach { nameBuilder.append("_${it.name.asString()}") }
|
||||||
|
descriptor.valueParameters.forEach { nameBuilder.append("_${it.type}") }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return@getOrPut scope.declareName(nameBuilder.toString())
|
||||||
|
})
|
||||||
|
}
|
||||||
+19
-4
@@ -5,12 +5,27 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
|
||||||
|
|
||||||
val IrFunctionSymbol.parameterCount get() = descriptor.valueParameters.size
|
val IrFunctionSymbol.parameterCount get() = descriptor.valueParameters.size
|
||||||
|
|
||||||
|
val IrFunctionSymbol.kind get() = descriptor.kind
|
||||||
|
|
||||||
|
val IrFunctionSymbol.modality get() = descriptor.modality
|
||||||
|
|
||||||
val IrConstructorSymbol.isPrimary get() = descriptor.isPrimary
|
val IrConstructorSymbol.isPrimary get() = descriptor.isPrimary
|
||||||
|
|
||||||
val IrValueSymbol.name get() = descriptor.name
|
val IrConstructorSymbol.constructedClassName get() = descriptor.constructedClass.name
|
||||||
|
|
||||||
|
val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass
|
||||||
|
|
||||||
|
val IrValueSymbol.isSpecial get() = descriptor.name.isSpecial
|
||||||
|
|
||||||
|
val IrSymbol.name get() = descriptor.name
|
||||||
|
|
||||||
|
val IrClassSymbol.kind get() = descriptor.kind
|
||||||
|
|
||||||
|
val IrClassSymbol.modality get() = descriptor.modality
|
||||||
|
|
||||||
|
val IrClassSymbol.isAny get() = KotlinBuiltIns.isAny(descriptor)
|
||||||
Reference in New Issue
Block a user