Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,13 @@ private val callsLoweringPhase = makeBodyLoweringPhase(
description = "Handle intrinsics"
)

private val doWhileRemoverPhase = makeBodyLoweringPhase(
::DoWhileRemover,
name = "DoWhileRemover",
description = "Remove do-while that Python doesn't have (replace with while)",
prerequisite = setOf(blockDecomposerLoweringPhase, suspendFunctionsLoweringPhase),
)

private val objectDeclarationLoweringPhase = makeDeclarationTransformerPhase(
::ObjectDeclarationLowering,
name = "ObjectDeclarationLowering",
Expand Down Expand Up @@ -728,6 +735,7 @@ private val loweringList = listOf(
objectUsageLoweringPhase,
captureStackTraceInThrowablesPhase,
callsLoweringPhase,
doWhileRemoverPhase,
cleanupLoweringPhase,
validateIrAfterLowering
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2022 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.
*/

package org.jetbrains.kotlin.ir.backend.py.lower

import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.ir.backend.py.PyIrBackendContext
import org.jetbrains.kotlin.ir.backend.py.ir.JsIrArithBuilder
import org.jetbrains.kotlin.ir.backend.py.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.builders.createTmpVariable
import org.jetbrains.kotlin.ir.builders.irComposite
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irSet
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrDoWhileLoop
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrWhileLoopImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid

class DoWhileTransformer(private val context: PyIrBackendContext, private val irSymbol: IrSymbol) : IrElementTransformerVoid() {

private val calculator = JsIrArithBuilder(context)
private val constTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
private val constFalse get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)

/*
Transform:

do:
<body>
while (<condition>)

To:

firstIterationLoopName = true
while firstIterationLoopName or (<condition>):
firstIterationLoopName = false
<body>
*/
override fun visitDoWhileLoop(loop: IrDoWhileLoop): IrExpression {
return context.createIrBuilder(irSymbol).irComposite {
val tmp = createTmpVariable(constTrue, nameHint = "firstIteration")
val newCondition = calculator.oror(irGet(tmp), loop.condition)
val newBody = irComposite {
+irSet(tmp, constFalse)
loop.body?.unaryPlus()
}

+IrWhileLoopImpl(loop.startOffset, loop.endOffset, loop.type, loop.origin).apply {
condition = newCondition
body = newBody
label = loop.label
}
}
}
}

class DoWhileRemover(private val context: PyIrBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(DoWhileTransformer(context, container.symbol))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,33 +215,9 @@ class IrElementToPyStatementTransformer : BaseIrElementToPyNodeTransformer<List<
).let { scopeContext.extractStatements() + it }
}

override fun visitDoWhileLoop(loop: IrDoWhileLoop, context: PyGenerationContext): List<stmt> {
// transform
//
// do { <body> } while (<condition>)
//
// like:
//
// while True:
// <body>
// if not <condition>:
// break
//
// TODO: support continue inside <body>
val scopeContext = context.newScope()
val body = loop.body?.accept(this, scopeContext).orEmpty()
val condition = If(
test = UnaryOp(Not, IrElementToPyExpressionTransformer().visitExpression(loop.condition, scopeContext)),
body = listOf(Break),
orelse = emptyList(),
)

return While(
test = Constant(value = constant("True"), kind = null),
body = body + condition,
orelse = emptyList(),
)
.let { scopeContext.extractStatements() + it }
override fun visitDoWhileLoop(loop: IrDoWhileLoop, context: PyGenerationContext): List<stmt> { // todo
return listOf(Expr(value = Name(id = identifier("visitDoWhileLoop $loop".toValidPythonSymbol()), ctx = Load)))
// error("DoWhile should have been eliminated in a lowering before executing ToPyTransformer")
}

override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression, context: PyGenerationContext): List<stmt> {
Expand Down
4 changes: 3 additions & 1 deletion python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ It will generate various reports and summaries:

![git-history-plot](box.tests/reports/git-history-plot.svg)

Current status: **2463**/5970 passed
Current status: **2468**/5970 passed

#### History (newest on top)

* after fully supporting do-while (with continue/break): **2468**/5970 (+5)

* after supporting static fields initialization: **2463**/5970 (+98: +102 passed, +4 failed because no support for unsigned numbers, chars, property delegates, any-to-string conversions)

* after supporting integer multiplication: **2365**/5970 (+23)
Expand Down
Loading