Skip to content

Commit

Permalink
Support secondary constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
SerVB authored and krzema12 committed Oct 16, 2021
1 parent d58ed9c commit 7163c12
Show file tree
Hide file tree
Showing 14 changed files with 1,363 additions and 1,250 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class IrDeclarationToPyTransformer : BaseIrElementToPyNodeTransformer<List<stmt>
}

override fun visitClass(declaration: IrClass, context: JsGenerationContext): List<stmt> {
return declaration.toPythonStatement(context)
return declaration.toPythonStatement(context.newDeclaration())
}

override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: JsGenerationContext): List<stmt> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.py.transformers.irToPy
import generated.Python.*
import org.jetbrains.kotlin.ir.backend.py.lower.InteropCallableReferenceLowering
import org.jetbrains.kotlin.ir.backend.py.utils.*
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable
Expand Down Expand Up @@ -179,6 +180,11 @@ class IrElementToPyExpressionTransformer : BaseIrElementToPyNodeTransformer<expr
val function = expression.symbol.owner
val arguments = translateCallArguments(expression, context, this)
val klass = function.parentAsClass
val fromPrimary = context.currentFunction is IrConstructor
val receiver = when (fromPrimary) {
true -> "self"
false -> context.currentFunction!!.valueParameters.last().name.asString().toValidPythonSymbol()
}

val className = context.getNameForClass(klass).ident.toValidPythonSymbol()
return Call(
Expand All @@ -187,7 +193,7 @@ class IrElementToPyExpressionTransformer : BaseIrElementToPyNodeTransformer<expr
attr = identifier("__init__"),
ctx = Load,
),
args = listOf(Name(identifier("self"), Load)) + arguments,
args = listOf(Name(identifier(receiver), Load)) + arguments,
keywords = emptyList(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.backend.py.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.py.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
Expand Down Expand Up @@ -224,13 +225,18 @@ class PyIntrinsicTransformers(backendContext: JsIrBackendContext) {
}

// prefixOp(intrinsics.jsTypeOf, JsUnaryOperator.TYPEOF)
//
// add(intrinsics.jsObjectCreate) { call, context ->
// val classToCreate = call.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
// val className = context.getNameForClass(classToCreate)
// val prototype = prototypeOf(className.makeRef())
// JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
// }

add(intrinsics.jsObjectCreate) { call, context ->
val classToCreate = call.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
val className = context.getNameForClass(classToCreate).ident.toValidPythonSymbol()
val pythonName = Name(identifier(className), Load)

Call(
func = Attribute(pythonName, identifier("__new__"), Load),
args = listOf(pythonName),
keywords = emptyList(),
)
}

add(intrinsics.jsClass) { call, context ->
val classifier: IrClassifierSymbol = call.getTypeArgument(0)!!.classifierOrFail
Expand Down Expand Up @@ -414,10 +420,10 @@ private fun MutableMap<IrSymbol, IrCallTransformer>.add(functionSymbol: IrSymbol
put(functionSymbol, t)
}

//private fun MutableMap<IrSymbol, IrCallTransformer>.add(function: IrSimpleFunction, t: IrCallTransformer) {
// put(function.symbol, t)
//}
//
private fun MutableMap<IrSymbol, IrCallTransformer>.add(function: IrSimpleFunction, t: IrCallTransformer) {
put(function.symbol, t)
}

//private fun MutableMap<IrSymbol, IrCallTransformer>.addIfNotNull(symbol: IrSymbol?, t: IrCallTransformer) {
// if (symbol == null) return
// put(symbol, t)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ import org.jetbrains.kotlin.js.backend.ast.JsName
fun expr.makeStmt(): stmt = Expr(value = this)

fun translateFunction(declaration: IrFunction, funcName: JsName, context: JsGenerationContext): FunctionDef {
val functionContext = context.newDeclaration(declaration) // todo: pass local name generator parameter

val isClassMethod = declaration.dispatchReceiverParameter != null
val isConstructor = declaration is IrConstructor
val extensionReceiverParameter = declaration.extensionReceiverParameter
val body = declaration.body?.accept(IrElementToPyStatementTransformer(), context) ?: listOf(Pass)
val body = declaration.body?.accept(IrElementToPyStatementTransformer(), functionContext) ?: listOf(Pass)
val args = declaration.valueParameters
.filter { !it.isVararg }
.map { valueParameter ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ val emptyScope: JsScope
class JsGenerationContext(
val currentFunction: IrFunction?,
val staticContext: JsStaticContext,
val localNames: LocalNameGenerator? = null
val localNames: LocalNameGenerator? = null,
val definedTypes: MutableSet<String> = mutableSetOf(),
): IrNamer by staticContext {
val definedTypes = mutableSetOf<String>()

fun newDeclaration(func: IrFunction? = null, localNames: LocalNameGenerator? = null): JsGenerationContext {
return JsGenerationContext(
currentFunction = func,
staticContext = staticContext,
localNames = localNames,
definedTypes = definedTypes,
)
}

val continuation
get() = if (isCoroutineDoResume()) {
Expand Down
4 changes: 3 additions & 1 deletion python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ It will generate various reports and summaries:

![git-history-plot](experiments/git-history-plot.svg)

Current status: **1952**/5787 passed
Current status: **1999**/5787 passed

#### History (newest on top)

* after supporting secondary constructors: **1999**/5787 passed (+47)

* after supporting some type checks: **1952**/5787 passed (+15)

* after supporting extension functions: **1937**/5787 passed (+70: +71 passed, +1 failed because no support for intRange)
Expand Down
22 changes: 22 additions & 0 deletions python/e2e-tests/constructors.consumer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from output import multi11, multi12, multi21, multi22, multi31, multi32, multi33, child
import output

multi11()
print(output.s)
multi12()
print(output.s)

multi21()
print(output.s)
multi22()
print(output.s)

multi31()
print(output.s)
multi32()
print(output.s)
multi33()
print(output.s)

child()
print(output.s)
89 changes: 89 additions & 0 deletions python/e2e-tests/constructors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/

var s = "abc"

class MultiConstructors1(a: Int) {

init {
s = "body 11"
}

constructor(b: String) : this(2) {
s = "body 12"
}
}

fun multi11() {
MultiConstructors1(1)
}

fun multi12() {
MultiConstructors1("a")
}

class MultiConstructors2 {

constructor(a: Int) {
s = "body 21"
}

constructor(b: String) {
s = "body 22"
}
}

fun multi21() {
MultiConstructors2(1)
}

fun multi22() {
MultiConstructors2("a")
}

class MultiConstructors3 {

constructor(a: Int) {
s = "body 31"
}

constructor(b: String) : this(3) {
s = "body 32"
}

constructor(b: Boolean) : this("c") {
s = "body 33"
}
}

fun multi31() {
MultiConstructors3(1)
}

fun multi32() {
MultiConstructors3("a")
}

fun multi33() {
MultiConstructors3(true)
}

abstract class BaseClass {

constructor(i: Int) {
s = "body base"
}
}

class ChildClass : BaseClass {

constructor(a: Int) : super(4) {
s = "body child"
}
}

fun child() {
ChildClass(123)
}
8 changes: 8 additions & 0 deletions python/e2e-tests/constructors.output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
body 11
body 12
body 21
body 22
body 31
body 32
body 33
body child
Loading

0 comments on commit 7163c12

Please sign in to comment.