diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/BlockCfg.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/BlockCfg.kt new file mode 100644 index 000000000..de876ffc5 --- /dev/null +++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/BlockCfg.kt @@ -0,0 +1,174 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+import org.jacodb.ets.utils.IdentityHashSet
+import java.util.IdentityHashMap
+
+data class Block(
+ val id: Int,
+ val statements: List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+sealed interface BlockStmt
+
+data object BlockNop : BlockStmt
+
+data class BlockAssign(
+ val target: Local,
+ val expr: Expr,
+) : BlockStmt
+
+data class BlockReturn(
+ val expr: Expr,
+) : BlockStmt
+
+data class BlockIf(
+ val condition: Expr,
+) : BlockStmt
diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/DSL.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/DSL.kt
new file mode 100644
index 000000000..2e09b3b87
--- /dev/null
+++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/DSL.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 UnitTestBot contributors (utbot.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+import org.jacodb.ets.utils.view
+
+private fun main() {
+ val prog = program {
+ assign(local("i"), param(0))
+
+ ifStmt(gt(local("i"), const(10.0))) {
+ ifStmt(eq(local("i"), const(42.0))) {
+ ret(local("i"))
+ `else` {
+ assign(local("i"), const(10.0))
+ }
+ }
+ nop()
+ }
+
+ label("loop")
+ ifStmt(gt(local("i"), const(0.0))) {
+ assign(local("i"), sub(local("i"), const(1.0)))
+ goto("loop")
+ `else` {
+ ret(local("i"))
+ }
+ }
+
+ ret(const(42.0)) // unreachable
+ }
+
+ val doView = false
+
+ println("PROGRAM:")
+ println("-----")
+ println(prog.toText())
+ println("-----")
+
+ println("=== PROGRAM:")
+ println(prog.toDot())
+ if (doView) view(prog.toDot(), name = "program")
+
+ val blockCfg = prog.toBlockCfg()
+ println("=== BLOCK CFG:")
+ println(blockCfg.toDot())
+ if (doView) view(blockCfg.toDot(), name = "block")
+
+ val linearCfg = blockCfg.linearize()
+ println("=== LINEARIZED CFG:")
+ println(linearCfg.toDot())
+ if (doView) view(linearCfg.toDot(), name = "linear")
+}
diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/Expr.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/Expr.kt
new file mode 100644
index 000000000..ca7acc420
--- /dev/null
+++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/Expr.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2022 UnitTestBot contributors (utbot.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+sealed interface Expr
+
+data class Local(val name: String) : Expr {
+ override fun toString() = name
+}
+
+data class Parameter(val index: Int) : Expr {
+ override fun toString() = "param($index)"
+}
+
+object ThisRef : Expr {
+ override fun toString() = "this"
+}
+
+data class Constant(val value: Double) : Expr {
+ override fun toString() = "const($value)"
+}
+
+enum class BinaryOperator {
+ AND, OR,
+ EQ, NEQ, LT, LTE, GT, GTE,
+ ADD, SUB, MUL, DIV
+}
+
+data class BinaryExpr(
+ val operator: BinaryOperator,
+ val left: Expr,
+ val right: Expr,
+) : Expr {
+ override fun toString() = "${operator.name.lowercase()}($left, $right)"
+}
+
+enum class UnaryOperator {
+ NOT, NEG
+}
+
+data class UnaryExpr(
+ val operator: UnaryOperator,
+ val expr: Expr,
+) : Expr {
+ override fun toString() = "${operator.name.lowercase()}($expr)"
+}
diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/LinearizedCfg.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/LinearizedCfg.kt
new file mode 100644
index 000000000..cc6078de5
--- /dev/null
+++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/LinearizedCfg.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 UnitTestBot contributors (utbot.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+data class LinearizedCfg(
+ val statements: List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+sealed interface Node
+
+data object Nop : Node
+
+data class Assign(
+ val target: Local,
+ val expr: Expr,
+) : Node
+
+data class Return(
+ val expr: Expr,
+) : Node
+
+data class If(
+ val condition: Expr,
+ val thenBranch: List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+data class Program(
+ val nodes: List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:Suppress("UnusedReceiverParameter")
+
+package org.jacodb.ets.dsl
+
+interface ProgramBuilder {
+ fun assign(target: Local, expr: Expr)
+ fun ret(expr: Expr)
+ fun ifStmt(condition: Expr, block: IfBuilder.() -> Unit)
+ fun nop()
+ fun label(name: String)
+ fun goto(label: String)
+}
+
+fun ProgramBuilder.local(name: String): Local = Local(name)
+fun ProgramBuilder.param(index: Int): Parameter = Parameter(index)
+fun ProgramBuilder.thisRef(): Expr = ThisRef
+fun ProgramBuilder.const(value: Double): Constant = Constant(value)
+
+fun ProgramBuilder.and(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.AND, left, right)
+fun ProgramBuilder.or(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.OR, left, right)
+fun ProgramBuilder.eq(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.EQ, left, right)
+fun ProgramBuilder.neq(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.NEQ, left, right)
+fun ProgramBuilder.lt(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.LT, left, right)
+fun ProgramBuilder.leq(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.LTE, left, right)
+fun ProgramBuilder.gt(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.GT, left, right)
+fun ProgramBuilder.geq(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.GTE, left, right)
+fun ProgramBuilder.add(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.ADD, left, right)
+fun ProgramBuilder.sub(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.SUB, left, right)
+fun ProgramBuilder.mul(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.MUL, left, right)
+fun ProgramBuilder.div(left: Expr, right: Expr): Expr = BinaryExpr(BinaryOperator.DIV, left, right)
+
+fun ProgramBuilder.not(expr: Expr): Expr = UnaryExpr(UnaryOperator.NOT, expr)
+fun ProgramBuilder.neg(expr: Expr): Expr = UnaryExpr(UnaryOperator.NEG, expr)
+
+class ProgramBuilderImpl : ProgramBuilder {
+ private val _nodes: MutableList
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+typealias StmtLocation = Int
+
+sealed interface Stmt {
+ val location: StmtLocation
+}
+
+data class NopStmt(
+ override val location: StmtLocation,
+) : Stmt
+
+data class AssignStmt(
+ override val location: StmtLocation,
+ val target: Local,
+ val expr: Expr,
+) : Stmt
+
+data class ReturnStmt(
+ override val location: StmtLocation,
+ val expr: Expr,
+) : Stmt
+
+data class IfStmt(
+ override val location: StmtLocation,
+ val condition: Expr,
+) : Stmt
diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/ToDot.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/ToDot.kt
new file mode 100644
index 000000000..8e04506b3
--- /dev/null
+++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/dsl/ToDot.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2022 UnitTestBot contributors (utbot.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.dsl
+
+import java.util.IdentityHashMap
+
+private fun Node.toDotLabel() = when (this) {
+ is Assign -> "$target := $expr"
+ is Return -> "return $expr"
+ is If -> "if ($condition)"
+ is Nop -> "nop"
+ is Label -> "label $name"
+ is Goto -> "goto $targetLabel"
+}
+
+fun Program.toDot(): String {
+ val lines = mutableListOf
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.graph
+
+import org.jacodb.ets.base.EtsAddExpr
+import org.jacodb.ets.base.EtsAndExpr
+import org.jacodb.ets.base.EtsAssignStmt
+import org.jacodb.ets.base.EtsClassType
+import org.jacodb.ets.base.EtsDivExpr
+import org.jacodb.ets.base.EtsEntity
+import org.jacodb.ets.base.EtsEqExpr
+import org.jacodb.ets.base.EtsGtEqExpr
+import org.jacodb.ets.base.EtsGtExpr
+import org.jacodb.ets.base.EtsIfStmt
+import org.jacodb.ets.base.EtsInstLocation
+import org.jacodb.ets.base.EtsLocal
+import org.jacodb.ets.base.EtsLtEqExpr
+import org.jacodb.ets.base.EtsLtExpr
+import org.jacodb.ets.base.EtsMulExpr
+import org.jacodb.ets.base.EtsNegExpr
+import org.jacodb.ets.base.EtsNopStmt
+import org.jacodb.ets.base.EtsNotEqExpr
+import org.jacodb.ets.base.EtsNotExpr
+import org.jacodb.ets.base.EtsNumberConstant
+import org.jacodb.ets.base.EtsOrExpr
+import org.jacodb.ets.base.EtsParameterRef
+import org.jacodb.ets.base.EtsReturnStmt
+import org.jacodb.ets.base.EtsStmt
+import org.jacodb.ets.base.EtsSubExpr
+import org.jacodb.ets.base.EtsThis
+import org.jacodb.ets.base.EtsType
+import org.jacodb.ets.base.EtsUnknownType
+import org.jacodb.ets.base.EtsValue
+import org.jacodb.ets.dsl.BinaryExpr
+import org.jacodb.ets.dsl.BinaryOperator
+import org.jacodb.ets.dsl.Block
+import org.jacodb.ets.dsl.BlockAssign
+import org.jacodb.ets.dsl.BlockCfg
+import org.jacodb.ets.dsl.BlockIf
+import org.jacodb.ets.dsl.BlockNop
+import org.jacodb.ets.dsl.BlockReturn
+import org.jacodb.ets.dsl.Constant
+import org.jacodb.ets.dsl.Expr
+import org.jacodb.ets.dsl.Local
+import org.jacodb.ets.dsl.Parameter
+import org.jacodb.ets.dsl.ThisRef
+import org.jacodb.ets.dsl.UnaryExpr
+import org.jacodb.ets.dsl.UnaryOperator
+import org.jacodb.ets.dsl.add
+import org.jacodb.ets.dsl.and
+import org.jacodb.ets.dsl.const
+import org.jacodb.ets.dsl.local
+import org.jacodb.ets.dsl.param
+import org.jacodb.ets.dsl.program
+import org.jacodb.ets.dsl.toBlockCfg
+import org.jacodb.ets.model.EtsClassSignature
+import org.jacodb.ets.model.EtsMethod
+import org.jacodb.ets.model.EtsMethodImpl
+import org.jacodb.ets.model.EtsMethodParameter
+import org.jacodb.ets.model.EtsMethodSignature
+import org.jacodb.ets.utils.toDot
+import org.jacodb.ets.utils.view
+import java.util.IdentityHashMap
+
+data class EtsBasicBlock(
+ val id: Int,
+ val statements: List
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.utils
+
+import org.jacodb.ets.base.EtsAssignStmt
+import org.jacodb.ets.base.EtsIfStmt
+import org.jacodb.ets.base.EtsNopStmt
+import org.jacodb.ets.base.EtsReturnStmt
+import org.jacodb.ets.base.EtsStmt
+import org.jacodb.ets.graph.EtsCfg
+
+private fun EtsStmt.toDotLabel(): String = when (this) {
+ is EtsNopStmt -> "nop"
+ is EtsAssignStmt -> "$lhv := $rhv"
+ is EtsReturnStmt -> "return $returnValue"
+ is EtsIfStmt -> "if ($condition)"
+ else -> this.toString() // TODO: support more statement types
+}
+
+fun EtsCfg.toDot(): String {
+ val lines = mutableListOf
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.utils
+
+import java.util.IdentityHashMap
+
+class IdentityHashSet
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.utils
+
+import java.nio.file.Path
+import kotlin.io.path.createTempDirectory
+import kotlin.io.path.div
+import kotlin.io.path.writeText
+
+fun view(
+ dot: String,
+ viewerCmd: String = when {
+ System.getProperty("os.name").startsWith("Mac") -> "open"
+ System.getProperty("os.name").startsWith("Win") -> "cmd /c start"
+ else -> "xdg-open"
+ },
+ dotCmd: String = "dot",
+ outputFormat: String = "svg",
+ name: String = "graph",
+ tempDir: Path = createTempDirectory("dot"),
+) {
+ val dotFile = tempDir / "$name.dot"
+ println("Writing DOT file to $dotFile")
+ dotFile.writeText(dot)
+ val outputFile = tempDir / "$name.$outputFormat"
+ println("Rendering ${outputFormat.uppercase()} to '$outputFile'...")
+ Runtime.getRuntime().exec("$dotCmd -T$outputFormat -o $outputFile $dotFile").waitFor()
+ println("Opening rendered file '$outputFile'...")
+ Runtime.getRuntime().exec("$viewerCmd $outputFile").waitFor()
+}
diff --git a/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsCfgDslTest.kt b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsCfgDslTest.kt
new file mode 100644
index 000000000..d410c083e
--- /dev/null
+++ b/jacodb-ets/src/test/kotlin/org/jacodb/ets/test/EtsCfgDslTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2022 UnitTestBot contributors (utbot.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jacodb.ets.test
+
+import org.jacodb.ets.base.EtsAssignStmt
+import org.jacodb.ets.base.EtsLocal
+import org.jacodb.ets.base.EtsNumberType
+import org.jacodb.ets.base.EtsUnknownType
+import org.jacodb.ets.dsl.add
+import org.jacodb.ets.dsl.const
+import org.jacodb.ets.dsl.local
+import org.jacodb.ets.dsl.lt
+import org.jacodb.ets.dsl.param
+import org.jacodb.ets.dsl.program
+import org.jacodb.ets.dsl.toBlockCfg
+import org.jacodb.ets.dsl.toDot
+import org.jacodb.ets.graph.linearize
+import org.jacodb.ets.graph.toDot
+import org.jacodb.ets.graph.toEtsBlockCfg
+import org.jacodb.ets.model.EtsClassSignature
+import org.jacodb.ets.model.EtsFileSignature
+import org.jacodb.ets.model.EtsMethodImpl
+import org.jacodb.ets.model.EtsMethodParameter
+import org.jacodb.ets.model.EtsMethodSignature
+import org.jacodb.ets.utils.toDot
+import org.junit.jupiter.api.Test
+
+class EtsCfgDslTest {
+ @Test
+ fun `test simple program`() {
+ val prog = program {
+ val i = local("i")
+
+ // i := arg(0)
+ assign(i, param(0))
+
+ // if (i < 10) i += 50
+ ifStmt(lt(i, const(10.0))) {
+ assign(i, add(i, const(50.0)))
+ }
+
+ // return i
+ ret(i)
+ }
+ println("program:\n${prog.toText()}")
+ val blockCfg = prog.toBlockCfg()
+ println("blockCfg:\n${blockCfg.toDot()}")
+
+ val locals = mutableListOf
"
+ }
+ val h = "" +
+ "
"
+ lines += " ${block.id} [label=<${h}>]"
+ } else {
+ val s = block.statements.joinToString("") { it.toDotLabel() + "\\l" }
+ lines += " ${block.id} [label=\"Block #${block.id}\\n$s\"]"
+ }
+ }
+
+ // Edges
+ blocks.forEach { block ->
+ val succs = successors[block.id]
+ if (succs != null) {
+ if (succs.isEmpty()) return@forEach
+ if (succs.size == 1) {
+ lines += " ${block.id} -> ${succs.single()}"
+ } else {
+ check(succs.size == 2)
+ val (trueBranch, falseBranch) = succs
+ lines += " ${block.id} -> $trueBranch [label=\"true\"]"
+ lines += " ${block.id} -> $falseBranch [label=\"false\"]"
+ }
+ }
+ }
+
+ lines += "}"
+ return lines.joinToString("\n")
+}
+
+private fun main() {
+ val method = EtsMethodImpl(
+ EtsMethodSignature(
+ enclosingClass = EtsClassSignature.DEFAULT,
+ name = "foo",
+ parameters = listOf(
+ EtsMethodParameter(
+ index = 0,
+ name = "x",
+ type = EtsUnknownType,
+ ),
+ EtsMethodParameter(
+ index = 1,
+ name = "y",
+ type = EtsUnknownType,
+ ),
+ ),
+ returnType = EtsUnknownType,
+ )
+ )
+ val p = program {
+ assign(local("x"), param(0))
+ assign(local("y"), param(1))
+ ifStmt(and(local("x"), local("y"))) {
+ ret(add(local("x"), local("y")))
+ }
+ ret(const(0.0))
+ }
+ val blockCfg = p.toBlockCfg()
+ val etsBlockCfg = blockCfg.toEtsBlockCfg(method)
+ println(etsBlockCfg.toDot())
+ view(etsBlockCfg.toDot(), name = "etsBlockCfg")
+ val etsCfg = etsBlockCfg.linearize()
+ println(etsCfg.toDot())
+ view(etsCfg.toDot(), name = "etsCfg")
+}
diff --git a/jacodb-ets/src/main/kotlin/org/jacodb/ets/graph/EtsCfg.kt b/jacodb-ets/src/main/kotlin/org/jacodb/ets/graph/EtsCfg.kt
index 48de74a06..9a444b58b 100644
--- a/jacodb-ets/src/main/kotlin/org/jacodb/ets/graph/EtsCfg.kt
+++ b/jacodb-ets/src/main/kotlin/org/jacodb/ets/graph/EtsCfg.kt
@@ -22,7 +22,7 @@ import org.jacodb.impl.cfg.graphs.GraphDominators
class EtsCfg(
val stmts: List " +
+ "" + "Block #${block.id}" + " " +
+ "" + s + "