JS: decomposition of "while" and "do while"

This commit is contained in:
Alexey Tsvetkov
2015-04-10 18:35:00 +03:00
parent 71ea487828
commit e80059e4a2
6 changed files with 111 additions and 3 deletions
@@ -77,6 +77,40 @@ class ExpressionDecomposer private (
}
override fun visit(x: JsWhile, ctx: JsContext<*>): Boolean {
x.process(true)
return false
}
override fun visit(x: JsDoWhile, ctx: JsContext<*>): Boolean {
x.process(false)
return false
}
private fun JsWhile.process(addBreakToBegin: Boolean) {
if (test !in containsExtractable) return
withNewAdditionalStatements {
test = accept(test)
val breakIfNotTest = JsIf(not(test), JsBreak())
// Body can be JsBlock or other JsStatement.
// Convert to statements list to avoid nested block.
val bodyStatements = flattenStatement(body)
if (addBreakToBegin) {
addStatement(breakIfNotTest)
addStatements(bodyStatements)
}
else {
addStatements(0, bodyStatements)
addStatement(breakIfNotTest)
}
body = additionalStatements.toStatement()
test = JsLiteral.TRUE
}
}
// TODO: comma operator?
override fun visit(x: JsBinaryOperation, ctx: JsContext<*>): Boolean {
x.arg1 = accept(x.arg1)
@@ -249,12 +283,15 @@ class ExpressionDecomposer private (
private fun addStatements(statements: List<JsStatement>) =
additionalStatements.addAll(statements)
private fun addStatements(index: Int, statements: List<JsStatement>) =
additionalStatements.addAll(index, statements)
private fun JsExpression.extractToTemporary(): JsExpression {
val tmp = Temporary(this)
addStatement(tmp.variable)
return tmp.nameRef
}
private inner class Temporary(val value: JsExpression? = null) {
val name: JsName = scope.declareTemporary()
@@ -320,8 +357,15 @@ private open class JsExpressionVisitor() : JsVisitorWithContextImpl() {
return false
}
override fun visit(x: JsWhile, ctx: JsContext<*>): Boolean = false
override fun visit(x: JsDoWhile, ctx: JsContext<*>): Boolean = false
override fun visit(x: JsWhile, ctx: JsContext<*>): Boolean {
x.test = accept(x.test)
return false
}
override fun visit(x: JsDoWhile, ctx: JsContext<*>): Boolean {
x.test = accept(x.test)
return false
}
override fun visit(x: JsArrayAccess, ctx: JsContext<*>): Boolean = true
override fun visit(x: JsArrayLiteral, ctx: JsContext<*>): Boolean = true
@@ -60,6 +60,14 @@ public var JsNameRef.qualifier: JsExpression?
get() = getQualifier()
set(value) = setQualifier(value)
public var JsWhile.test: JsExpression
get() = getCondition()
set(value) = setCondition(value)
public var JsWhile.body: JsStatement
get() = getBody()
set(value) = setBody(value)
public var JsArrayAccess.index: JsExpression
get() = getIndexExpression()
set(value) = setIndexExpression(value)
@@ -0,0 +1,14 @@
package foo
fun box(): String {
var c = 2
do {
if (c > 4) throw Exception("Timeout!")
c++
} while (buzz(c) < 4)
assertEquals("buzz(3);buzz(4);", pullLog())
return "OK"
}
@@ -0,0 +1,14 @@
package foo
fun box(): String {
var c = 1
do {
if (c > 4) throw Exception("Timeout!")
c++
} while (fizz(c) % 2 == 0 || buzz(c) % 3 == 0)
assertEquals("fizz(2);fizz(3);buzz(3);fizz(4);fizz(5);buzz(5);", pullLog())
return "OK"
}
@@ -0,0 +1,14 @@
package foo
fun box(): String {
var c = 2
while (buzz(c) <= 4) {
if (c > 4) throw Exception("Timeout!")
c++
}
assertEquals("buzz(2);buzz(3);buzz(4);buzz(5);", pullLog())
return "OK"
}
@@ -0,0 +1,14 @@
package foo
fun box(): String {
var c = 2
while (fizz(c) % 2 == 0 || buzz(c) % 3 == 0) {
if (c > 4) throw Exception("Timeout!")
c++
}
assertEquals("fizz(2);fizz(3);buzz(3);fizz(4);fizz(5);buzz(5);", pullLog())
return "OK"
}