JS: decomposition of ternary operator

This commit is contained in:
Alexey Tsvetkov
2015-04-10 18:09:51 +03:00
parent 3782b9d382
commit fd844ad6e3
7 changed files with 137 additions and 0 deletions
@@ -97,6 +97,35 @@ class ExpressionDecomposer private (
index = accept(index)
}
override fun visit(x: JsConditional, ctx: JsContext<*>): Boolean {
x.process(ctx)
return false
}
private fun JsConditional.process(ctx: JsContext<*>) {
test = accept(test)
if (then !in containsExtractable && otherwise !in containsExtractable) return
val tmp = Temporary()
addStatement(tmp.variable)
val thenBlock = withNewAdditionalStatements {
then = accept(then)
addStatement(tmp.assign(then))
additionalStatements.toStatement()
}
val elseBlock = withNewAdditionalStatements {
otherwise = accept(otherwise)
addStatement(tmp.assign(otherwise))
additionalStatements.toStatement()
}
val lazyEval = JsIf(test, thenBlock, elseBlock)
addStatement(lazyEval)
ctx.replaceMe(tmp.nameRef)
}
override fun visit(x: JsInvocation, ctx: JsContext<*>): Boolean {
CallableInvocationAdapter(x).process()
return false
@@ -153,9 +182,21 @@ class ExpressionDecomposer private (
}
}
inline
private fun withNewAdditionalStatements<T>(fn: ()->T): T {
val backup = additionalStatements
additionalStatements = SmartList<JsStatement>()
val result = fn()
additionalStatements = backup
return result
}
private fun addStatement(statement: JsStatement) =
additionalStatements.add(statement)
private fun addStatements(statements: List<JsStatement>) =
additionalStatements.addAll(statements)
private fun JsExpression.extractToTemporary(): JsExpression {
val tmp = Temporary(this)
addStatement(tmp.variable)
@@ -294,3 +335,10 @@ private fun JsNode.withParentsOfNodes(nodes: Set<JsNode>): Set<JsNode> {
visitor.accept(this)
return visitor.matched
}
private fun List<JsStatement>.toStatement(): JsStatement =
when (size()) {
0 -> JsEmpty
1 -> get(0)
else -> JsBlock(this)
}
@@ -63,3 +63,15 @@ public var JsArrayAccess.index: JsExpression
public var JsArrayAccess.array: JsExpression
get() = getArrayExpression()
set(value) = setArrayExpression(value)
public var JsConditional.test: JsExpression
get() = getTestExpression()
set(value) = setTestExpression(value)
public var JsConditional.then: JsExpression
get() = getThenExpression()
set(value) = setThenExpression(value)
public var JsConditional.otherwise: JsExpression
get() = getElseExpression()
set(value) = setElseExpression(value)
@@ -0,0 +1,13 @@
package foo
fun test(x: Boolean): Boolean =
if (fizz(x)) buzz(true) else buzz(false)
fun box(): String {
assertEquals(true, test(true))
assertEquals("fizz(true);buzz(true);", pullLog())
assertEquals(false, test(false))
assertEquals("fizz(false);buzz(false);", pullLog())
return "OK"
}
@@ -0,0 +1,14 @@
package foo
fun test(x: Boolean?): Boolean = fizz(x) ?: buzz(true)
fun box(): String {
assertEquals(true, test(null))
assertEquals("fizz(null);buzz(true);", pullLog())
assertEquals(false, test(false))
assertEquals("fizz(false);", pullLog())
assertEquals(true, test(true))
assertEquals("fizz(true);", pullLog())
return "OK"
}
@@ -0,0 +1,23 @@
package foo
fun test(x: Boolean, y: Boolean): Int =
if (fizz(x))
if (fizz(y)) buzz(1) else buzz(2)
else
if (fizz(y)) buzz(3) else buzz(4)
fun box(): String {
assertEquals(1, test(true, true))
assertEquals("fizz(true);fizz(true);buzz(1);", pullLog())
assertEquals(2, test(true, false))
assertEquals("fizz(true);fizz(false);buzz(2);", pullLog())
assertEquals(3, test(false, true))
assertEquals("fizz(false);fizz(true);buzz(3);", pullLog())
assertEquals(4, test(false, false))
assertEquals("fizz(false);fizz(false);buzz(4);", pullLog())
return "OK"
}
@@ -0,0 +1,13 @@
package foo
fun test(x: Boolean): Boolean =
if (buzz(x)) buzz(true) else fizz(false)
fun box(): String {
assertEquals(true, test(true))
assertEquals("buzz(true);buzz(true);", pullLog())
assertEquals(false, test(false))
assertEquals("buzz(false);fizz(false);", pullLog())
return "OK"
}
@@ -0,0 +1,14 @@
package foo
fun test(x: Boolean?): Boolean = buzz(x) ?: fizz(true)
fun box(): String {
assertEquals(true, test(null))
assertEquals("buzz(null);fizz(true);", pullLog())
assertEquals(false, test(false))
assertEquals("buzz(false);", pullLog())
assertEquals(true, test(true))
assertEquals("buzz(true);", pullLog())
return "OK"
}