Inline refactoring: more templates for captured fields
Support of complex lambda inlining cases
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
import builders.*
|
||||
|
||||
inline fun testAllInline(f: () -> String) : String {
|
||||
val args = array("1", "2", "3")
|
||||
val result =
|
||||
html {
|
||||
val htmlVal = 0
|
||||
head {
|
||||
title { +"XML encoding with Kotlin" }
|
||||
}
|
||||
body {
|
||||
var bodyVar = 1
|
||||
h1 { +"XML encoding with Kotlin" }
|
||||
p { +"this format can be used as an alternative markup to XML" }
|
||||
|
||||
// an element with attributes and text content
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
|
||||
// mixed content
|
||||
p {
|
||||
+"This is some"
|
||||
b { +"mixed" }
|
||||
+"text. For more see the"
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
+"project"
|
||||
}
|
||||
p { +"some text" }
|
||||
|
||||
// content generated from command-line arguments
|
||||
p {
|
||||
+"Command line arguments were:"
|
||||
ul {
|
||||
for (arg in args)
|
||||
li { +arg; +"$htmlVal"; +"$bodyVar"; +"${f()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString()!!
|
||||
}
|
||||
|
||||
inline fun testHtmlNoInline(f: () -> String) : String {
|
||||
val args = array("1", "2", "3")
|
||||
val result =
|
||||
htmlNoInline() {
|
||||
val htmlVal = 0
|
||||
head {
|
||||
title { +"XML encoding with Kotlin" }
|
||||
}
|
||||
body {
|
||||
var bodyVar = 1
|
||||
h1 { +"XML encoding with Kotlin" }
|
||||
p { +"this format can be used as an alternative markup to XML" }
|
||||
|
||||
// an element with attributes and text content
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
|
||||
// mixed content
|
||||
p {
|
||||
+"This is some"
|
||||
b { +"mixed" }
|
||||
+"text. For more see the"
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
+"project"
|
||||
}
|
||||
p { +"some text" }
|
||||
|
||||
// content generated from command-line arguments
|
||||
p {
|
||||
+"Command line arguments were:"
|
||||
ul {
|
||||
for (arg in args)
|
||||
li { +arg; +"$htmlVal"; +"$bodyVar"; +"${f()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString()!!
|
||||
}
|
||||
|
||||
inline fun testBodyNoInline(f: () -> String) : String {
|
||||
val args = array("1", "2", "3")
|
||||
val result =
|
||||
html {
|
||||
val htmlVal = 0
|
||||
head {
|
||||
title { +"XML encoding with Kotlin" }
|
||||
}
|
||||
bodyNoInline {
|
||||
var bodyVar = 1
|
||||
h1 { +"XML encoding with Kotlin" }
|
||||
p { +"this format can be used as an alternative markup to XML" }
|
||||
|
||||
// an element with attributes and text content
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
|
||||
// mixed content
|
||||
p {
|
||||
+"This is some"
|
||||
b { +"mixed" }
|
||||
+"text. For more see the"
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
+"project"
|
||||
}
|
||||
p { +"some text" }
|
||||
|
||||
// content generated from command-line arguments
|
||||
p {
|
||||
+"Command line arguments were:"
|
||||
ul {
|
||||
for (arg in args)
|
||||
li { +arg; +"$htmlVal"; +"$bodyVar"; +"${f()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString()!!
|
||||
}
|
||||
|
||||
inline fun testBodyHtmlNoInline(f: () -> String) : String {
|
||||
val args = array("1", "2", "3")
|
||||
val result =
|
||||
htmlNoInline {
|
||||
val htmlVal = 0
|
||||
head {
|
||||
title { +"XML encoding with Kotlin" }
|
||||
}
|
||||
bodyNoInline {
|
||||
var bodyVar = 1
|
||||
h1 { +"XML encoding with Kotlin" }
|
||||
p { +"this format can be used as an alternative markup to XML" }
|
||||
|
||||
// an element with attributes and text content
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
|
||||
// mixed content
|
||||
p {
|
||||
+"This is some"
|
||||
b { +"mixed" }
|
||||
+"text. For more see the"
|
||||
a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
|
||||
+"project"
|
||||
}
|
||||
p { +"some text" }
|
||||
|
||||
// content generated from command-line arguments
|
||||
p {
|
||||
+"Command line arguments were:"
|
||||
ul {
|
||||
for (arg in args)
|
||||
li { +arg; +"$htmlVal"; +"$bodyVar"; +"${f()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString()!!
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var expected = testAllInline({"x"});
|
||||
print(expected + " " + testHtmlNoInline({"x"}))
|
||||
|
||||
if (expected != testHtmlNoInline({"x"})) return "fail 1: ${testHtmlNoInline({"x"})}\nbut expected\n${expected} "
|
||||
if (expected != testBodyNoInline({"x"})) return "fail 2: ${testBodyNoInline({"x"})}\nbut expected\n${expected} "
|
||||
if (expected != testBodyHtmlNoInline({"x"})) return "fail 3: ${testBodyHtmlNoInline({"x"})}\nbut expected\n${expected} "
|
||||
|
||||
var captured = "x"
|
||||
if (expected != testHtmlNoInline({captured})) return "fail 4: ${testHtmlNoInline({captured})}\nbut expected\n${expected} "
|
||||
if (expected != testBodyNoInline({captured})) return "fail 5: ${testBodyNoInline({captured})}\nbut expected\n${expected} "
|
||||
if (expected != testBodyHtmlNoInline({captured})) return "fail 6: ${testBodyHtmlNoInline({captured})}\nbut expected\n${expected} "
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package builders
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
|
||||
trait Element {
|
||||
fun render(builder: StringBuilder, indent: String)
|
||||
|
||||
override fun toString(): String {
|
||||
val builder = StringBuilder()
|
||||
render(builder, "")
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class TextElement(val text: String) : Element {
|
||||
override fun render(builder: StringBuilder, indent: String) {
|
||||
builder.append("$indent$text\n")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Tag(val name: String) : Element {
|
||||
val children = ArrayList<Element>()
|
||||
val attributes = HashMap<String, String>()
|
||||
|
||||
inline protected fun initTag<T : Element>(tag: T, init: T.() -> Unit): T {
|
||||
tag.init()
|
||||
children.add(tag)
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun render(builder: StringBuilder, indent: String) {
|
||||
builder.append("$indent<$name${renderAttributes()}>\n")
|
||||
for (c in children) {
|
||||
c.render(builder, indent + " ")
|
||||
}
|
||||
builder.append("$indent</$name>\n")
|
||||
}
|
||||
|
||||
private fun renderAttributes(): String? {
|
||||
val builder = StringBuilder()
|
||||
for (a in attributes.keySet()) {
|
||||
builder.append(" $a=\"${attributes[a]}\"")
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TagWithText(name: String) : Tag(name) {
|
||||
fun String.plus() {
|
||||
children.add(TextElement(this))
|
||||
}
|
||||
}
|
||||
|
||||
class HTML() : TagWithText("html") {
|
||||
inline fun head(init: Head.() -> Unit) = initTag(Head(), init)
|
||||
|
||||
inline fun body(init: Body.() -> Unit) = initTag(Body(), init)
|
||||
|
||||
fun bodyNoInline(init: Body.() -> Unit) = initTag(Body(), init)
|
||||
}
|
||||
|
||||
class Head() : TagWithText("head") {
|
||||
inline fun title(init: Title.() -> Unit) = initTag(Title(), init)
|
||||
}
|
||||
|
||||
class Title() : TagWithText("title")
|
||||
|
||||
abstract class BodyTag(name: String) : TagWithText(name) {
|
||||
inline fun b(init: B.() -> Unit) = initTag(B(), init)
|
||||
inline fun p(init: P.() -> Unit) = initTag(P(), init)
|
||||
inline fun pNoInline(init: P.() -> Unit) = initTag(P(), init)
|
||||
inline fun h1(init: H1.() -> Unit) = initTag(H1(), init)
|
||||
inline fun ul(init: UL.() -> Unit) = initTag(UL(), init)
|
||||
inline fun a(href: String, init: A.() -> Unit) {
|
||||
val a = initTag(A(), init)
|
||||
a.href = href
|
||||
}
|
||||
}
|
||||
|
||||
class Body() : BodyTag("body")
|
||||
class UL() : BodyTag("ul") {
|
||||
inline fun li(init: LI.() -> Unit) = initTag(LI(), init)
|
||||
}
|
||||
|
||||
class B() : BodyTag("b")
|
||||
class LI() : BodyTag("li")
|
||||
class P() : BodyTag("p")
|
||||
class H1() : BodyTag("h1")
|
||||
class A() : BodyTag("a") {
|
||||
public var href: String
|
||||
get() = attributes["href"]!!
|
||||
set(value) {
|
||||
attributes["href"] = value
|
||||
}
|
||||
}
|
||||
|
||||
inline fun html(init: HTML.() -> Unit): HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
|
||||
fun htmlNoInline(init: HTML.() -> Unit): HTML {
|
||||
val html = HTML()
|
||||
html.init()
|
||||
return html
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import test.*
|
||||
|
||||
fun test1(param: String): String {
|
||||
var result = "fail1"
|
||||
mfun(param) { a ->
|
||||
noInlineFun(param) { a ->
|
||||
concat("start") {
|
||||
result = doSmth(a).toString()
|
||||
}
|
||||
@@ -11,9 +11,43 @@ fun test1(param: String): String {
|
||||
return result
|
||||
}
|
||||
|
||||
fun test11(param: String): String {
|
||||
var result = "fail1"
|
||||
noInlineFun("stub") { a ->
|
||||
concat("start") {
|
||||
result = doSmth(param).toString()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
inline fun test2(param: () -> String): String {
|
||||
var result = "fail1"
|
||||
noInlineFun("stub") { a ->
|
||||
concat(param()) {
|
||||
result = doSmth(param()).toString()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
inline fun test22(param: () -> String): String {
|
||||
var result = "fail1"
|
||||
{{result = param()}()}()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
if (test1("start") != "start") return "fail1"
|
||||
if (test1("nostart") != "nostart") return "fail2"
|
||||
if (test1("start") != "start") return "fail1: ${test1("start")}"
|
||||
if (test1("nostart") != "nostart") return "fail2: ${test1("nostart")}"
|
||||
if (test11("start") != "start") return "fail3: ${test11("start")}"
|
||||
|
||||
if (test2({"start"}) != "start") return "fail4: ${test2({"start"})}"
|
||||
if (test22({"start"}) != "start") return "fail5: ${test22({"start"})}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -4,7 +4,7 @@ fun concat(suffix: String, l: (s: String) -> Unit) {
|
||||
l(suffix)
|
||||
}
|
||||
|
||||
fun <T> mfun(arg: T, f: (T) -> Unit) {
|
||||
fun <T> noInlineFun(arg: T, f: (T) -> Unit) {
|
||||
f(arg)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import test.*
|
||||
|
||||
inline fun test1(param: () -> String): String {
|
||||
var result = "fail"
|
||||
inlineFun("1") { c ->
|
||||
{
|
||||
inlineFun("2") { a ->
|
||||
{
|
||||
{
|
||||
result = param() + c + a
|
||||
}()
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
inline fun test2(param: () -> String): String {
|
||||
var result = "fail"
|
||||
inlineFun("2") { a ->
|
||||
{
|
||||
{
|
||||
result = param() + a
|
||||
}()
|
||||
}()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
inline fun test3(param: () -> String): String {
|
||||
var result = "fail"
|
||||
inlineFun("2") { d ->
|
||||
inlineFun("1") { c ->
|
||||
{
|
||||
inlineFun("2") { a ->
|
||||
{
|
||||
{
|
||||
result = param() + c + a
|
||||
}()
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
if (test1({"start"}) != "start12") return "fail1: ${test1({"start"})}"
|
||||
if (test2({"start"}) != "start2") return "fail2: ${test2({"start"})}"
|
||||
if (test3({"start"}) != "start12") return "fail3: ${test3({"start"})}"
|
||||
|
||||
var captured1 = "sta";
|
||||
val captured2 = "rt";
|
||||
if (test1({captured1 + captured2}) != "start12") return "fail4: ${test1({captured1 + captured2})}"
|
||||
if (test2({captured1 + captured2}) != "start2") return "fail5: ${test2({captured1 + captured2})}"
|
||||
if (test3({captured1 + captured2}) != "start12") return "fail6: ${test3({captured1 + captured2})}"
|
||||
|
||||
return {
|
||||
if (test1 { captured1 + captured2 } != "start12") "fail7: ${test1 { captured1 + captured2 }}"
|
||||
else if (test2 { captured1 + captured2 } != "start2") "fail8: ${test2 { captured1 + captured2 }}"
|
||||
else if (test3 { captured1 + captured2 } != "start12") "fail9: ${test3 { captured1 + captured2 }}"
|
||||
else "OK"
|
||||
} ()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
inline fun <T> inlineFun(arg: T, f: (T) -> Unit) {
|
||||
f(arg)
|
||||
}
|
||||
@@ -6,7 +6,22 @@ fun Data.test1(d: Data) : Long {
|
||||
with(input) {
|
||||
result = use<Long>{
|
||||
val output = Output(d)
|
||||
useNoInline<Long>{
|
||||
use<Long>{
|
||||
data()
|
||||
copyTo(output, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun Data.test2(d: Data) : Long {
|
||||
val input = Input(this)
|
||||
var result = 10.toLong()
|
||||
with2(input) {
|
||||
result = use<Long>{
|
||||
val output = Output(d)
|
||||
useNoInline<Long>{
|
||||
data()
|
||||
copyTo(output, 10)
|
||||
}
|
||||
@@ -21,5 +36,8 @@ fun box(): String {
|
||||
val result = Data().test1(Data())
|
||||
if (result != 100.toLong()) return "test1: ${result}"
|
||||
|
||||
val result2 = Data().test2(Data())
|
||||
if (result2 != 100.toLong()) return "test2: ${result2}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -25,3 +25,6 @@ public fun <R> useNoInline(block: ()-> R) : R {
|
||||
public fun Input.copyTo(output: Output, size: Int): Long {
|
||||
return output.doOutput(this.data()).toLong()
|
||||
}
|
||||
|
||||
|
||||
public inline fun with2<T>(receiver : T, body : T.() -> Unit) : Unit = {receiver.body()}()
|
||||
|
||||
Reference in New Issue
Block a user