aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-02-13 15:01:03 +0100
committerGitHub <noreply@github.com>2017-02-13 15:01:03 +0100
commit07b67a8416c501d7f7b37442f3a294d9f9252895 (patch)
tree098772eb9ae3e5a64993e1b172505035c9b887ac
parent5bcbad29a368bf6a06230aed73488995e733d97a (diff)
parent1489eff397482fec14e5da54e4654278a5c6f7dc (diff)
downloaddotty-07b67a8416c501d7f7b37442f3a294d9f9252895.tar.gz
dotty-07b67a8416c501d7f7b37442f3a294d9f9252895.tar.bz2
dotty-07b67a8416c501d7f7b37442f3a294d9f9252895.zip
Merge pull request #1951 from dotty-staging/fix-1484
fix #1484: position of while incorrect in debug
-rw-r--r--.drone.yml1
-rw-r--r--.drone.yml.sig2
-rw-r--r--.gitignore1
-rwxr-xr-xbin/dotr17
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala4
-rwxr-xr-xcompiler/test/debug/Gen13
-rwxr-xr-xcompiler/test/debug/Gen.scala171
-rwxr-xr-xcompiler/test/debug/test21
-rw-r--r--docs/docs/contributing/debug-tests.md124
-rw-r--r--tests/debug/for.scala16
-rw-r--r--tests/debug/function.scala14
-rw-r--r--tests/debug/if.scala20
-rw-r--r--tests/debug/method.scala14
-rw-r--r--tests/debug/nested-method.scala15
-rw-r--r--tests/debug/sequence.scala11
-rw-r--r--tests/debug/tailrec.scala17
-rw-r--r--tests/debug/while.scala14
17 files changed, 471 insertions, 4 deletions
diff --git a/.drone.yml b/.drone.yml
index 83309ef4e..935297a5b 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -7,6 +7,7 @@ pipeline:
- ln -s /var/cache/drone/ivy2 "$HOME/.ivy2"
- ./scripts/update-scala-library
- sbt -J-Xmx4096m -J-XX:ReservedCodeCacheSize=512m -J-XX:MaxMetaspaceSize=1024m -Ddotty.drone.mem=4096m "${TEST}"
+ - ./compiler/test/debug/test
when:
branch:
exclude: gh-pages
diff --git a/.drone.yml.sig b/.drone.yml.sig
index 1093928f0..63609e5c8 100644
--- a/.drone.yml.sig
+++ b/.drone.yml.sig
@@ -1 +1 @@
-eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIGxuIC1zIC92YXIvY2FjaGUvZHJvbmUvc2NhbGEtc2NhbGEgc2NhbGEtc2NhbGEKICAgICAgLSBsbiAtcyAvdmFyL2NhY2hlL2Ryb25lL2l2eTIgIiRIT01FLy5pdnkyIgogICAgICAtIC4vc2NyaXB0cy91cGRhdGUtc2NhbGEtbGlicmFyeQogICAgICAtIHNidCAtSi1YbXg0MDk2bSAtSi1YWDpSZXNlcnZlZENvZGVDYWNoZVNpemU9NTEybSAtSi1YWDpNYXhNZXRhc3BhY2VTaXplPTEwMjRtIC1EZG90dHkuZHJvbmUubWVtPTQwOTZtICIke1RFU1R9IgogICAgd2hlbjoKICAgICAgYnJhbmNoOgogICAgICAgIGV4Y2x1ZGU6IGdoLXBhZ2VzCgogIGRvY3VtZW50YXRpb246CiAgICBpbWFnZTogbGFtcGVwZmwvZG90dHk6bGF0ZXN0CiAgICBwdWxsOiB0cnVlCiAgICBjb21tYW5kczoKICAgICAgLSAuL3Byb2plY3Qvc2NyaXB0cy9nZW5Eb2NzICIke1RFU1R9IiAkQk9UX1BBU1MKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCgogIGdpdHRlcjoKICAgIGltYWdlOiBwbHVnaW5zL2dpdHRlcgogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKICAgICAgc3RhdHVzOiBjaGFuZ2VkCgogIHNsYWNrOgogICAgaW1hZ2U6IHBsdWdpbnMvc2xhY2sKICAgIGNoYW5uZWw6IGRvdHR5CiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBzdGF0dXM6IGNoYW5nZWQKCm1hdHJpeDoKICBURVNUOgogICAgLSA7dGVzdDtkb3R0eS1iaW4tdGVzdHMvdGVzdAogICAgLSA7cHVibGlzaExvY2FsO2RvdHR5LWJvb3RzdHJhcHBlZC90ZXN0CiAgICAtIHBhcnRlc3Qtb25seS1uby1ib290c3RyYXAgLS1zaG93LWRpZmYgLS12ZXJib3NlCiAgICAtIHBhcnRlc3Qtb25seSAtLXNob3ctZGlmZiAtLXZlcmJvc2UK.VRqZiSgeE6OumPlEvs4TWfxIHNOEVjR_ZmyBmapxZ-U \ No newline at end of file
+eyJhbGciOiJIUzI1NiJ9.cGlwZWxpbmU6CiAgdGVzdDoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIGxuIC1zIC92YXIvY2FjaGUvZHJvbmUvc2NhbGEtc2NhbGEgc2NhbGEtc2NhbGEKICAgICAgLSBsbiAtcyAvdmFyL2NhY2hlL2Ryb25lL2l2eTIgIiRIT01FLy5pdnkyIgogICAgICAtIC4vc2NyaXB0cy91cGRhdGUtc2NhbGEtbGlicmFyeQogICAgICAtIHNidCAtSi1YbXg0MDk2bSAtSi1YWDpSZXNlcnZlZENvZGVDYWNoZVNpemU9NTEybSAtSi1YWDpNYXhNZXRhc3BhY2VTaXplPTEwMjRtIC1EZG90dHkuZHJvbmUubWVtPTQwOTZtICIke1RFU1R9IgogICAgICAtIC4vY29tcGlsZXIvdGVzdC9kZWJ1Zy90ZXN0CiAgICB3aGVuOgogICAgICBicmFuY2g6CiAgICAgICAgZXhjbHVkZTogZ2gtcGFnZXMKCiAgZG9jdW1lbnRhdGlvbjoKICAgIGltYWdlOiBsYW1wZXBmbC9kb3R0eTpsYXRlc3QKICAgIHB1bGw6IHRydWUKICAgIGNvbW1hbmRzOgogICAgICAtIC4vcHJvamVjdC9zY3JpcHRzL2dlbkRvY3MgIiR7VEVTVH0iICRCT1RfUEFTUwogICAgd2hlbjoKICAgICAgYnJhbmNoOiBtYXN0ZXIKCiAgZ2l0dGVyOgogICAgaW1hZ2U6IHBsdWdpbnMvZ2l0dGVyCiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBzdGF0dXM6IGNoYW5nZWQKCiAgc2xhY2s6CiAgICBpbWFnZTogcGx1Z2lucy9zbGFjawogICAgY2hhbm5lbDogZG90dHkKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCiAgICAgIHN0YXR1czogY2hhbmdlZAoKbWF0cml4OgogIFRFU1Q6CiAgICAtIDt0ZXN0O2RvdHR5LWJpbi10ZXN0cy90ZXN0CiAgICAtIDtwdWJsaXNoTG9jYWw7ZG90dHktYm9vdHN0cmFwcGVkL3Rlc3QKICAgIC0gcGFydGVzdC1vbmx5LW5vLWJvb3RzdHJhcCAtLXNob3ctZGlmZiAtLXZlcmJvc2UKICAgIC0gcGFydGVzdC1vbmx5IC0tc2hvdy1kaWZmIC0tdmVyYm9zZQo.NgZCPjkR9Z1A96-ryvHIVJOsL9GI6aIvU6tGC_hv5Lo \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 1a0b1b6a7..9842e0c6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,4 +52,5 @@ build/
# Put local stuff here
local/
+compiler/test/debug/Gen.jar
diff --git a/bin/dotr b/bin/dotr
index f00760006..e5a632565 100755
--- a/bin/dotr
+++ b/bin/dotr
@@ -8,6 +8,10 @@ fi
DOTTY_ROOT="$(dirname "$DOTTY_ROOT")"
DOTTY_ROOT="$( cd "$DOTTY_ROOT" >& /dev/null && pwd )/.." # absolute
+# debug
+DEBUG_STR=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
+DEBUG=
+
# Load common functions and variables
source "$DOTTY_ROOT"/bin/common
@@ -24,10 +28,21 @@ function runMain {
echo "java bin not detected - please specify with \$JAVA_BIN or install java to a default location"
exit 1
else
- eval "$jbin $CLASS_PATH $@"
+ eval "$jbin $DEBUG $CLASS_PATH $@"
fi
}
+# parse command line params -d to enable debugging
+while getopts "dx" opt; do
+ case "$opt" in
+ d)
+ DEBUG="$DEBUG_STR"
+ ;;
+ esac
+done
+
+shift $((OPTIND-1))
+
first_arg="$1"
if [ -z "$1" ]; then
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index eda4a12dc..e3102fda2 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -991,12 +991,12 @@ object desugar {
else Apply(ref(tupleTypeRef.classSymbol.companionModule.valRef), ts)
case WhileDo(cond, body) =>
// { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
- val call = Apply(Ident(nme.WHILE_PREFIX), Nil)
+ val call = Apply(Ident(nme.WHILE_PREFIX), Nil).withPos(tree.pos)
val rhs = If(cond, Block(body, call), unitLiteral)
labelDefAndCall(nme.WHILE_PREFIX, rhs, call)
case DoWhile(body, cond) =>
// { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() }
- val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil)
+ val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil).withPos(tree.pos)
val rhs = Block(body, If(cond, call, unitLiteral))
labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call)
case ForDo(enums, body) =>
diff --git a/compiler/test/debug/Gen b/compiler/test/debug/Gen
new file mode 100755
index 000000000..c5c4d6ec6
--- /dev/null
+++ b/compiler/test/debug/Gen
@@ -0,0 +1,13 @@
+#! /usr/bin/env bash
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+SOURCE=$DIR/Gen.scala
+CLASS=./Gen.class
+
+if [ ! -e $CLASS ] || [ $SOURCE -nt $CLASS ]; then
+ ./bin/dotc $DIR/Gen.scala
+fi
+
+./bin/dotr Gen $@
+
diff --git a/compiler/test/debug/Gen.scala b/compiler/test/debug/Gen.scala
new file mode 100755
index 000000000..f7a5cc432
--- /dev/null
+++ b/compiler/test/debug/Gen.scala
@@ -0,0 +1,171 @@
+import scala.io.Source
+import scala.collection.mutable.ListBuffer
+
+/** Automate testing debuggability of generated code using JDB and expect
+ *
+ * The debugging information is annotated as comments to the code in brackets:
+ *
+ * val x = f(3) // [break] [next: line=5]
+ * val y = 5
+ *
+ * 1. A jdb command must be wrapped in brackets, like `[step]`. All jdb commands can be used.
+ * 2. To check output of jdb for a command, use `[cmd: expect]`.
+ * 3. If `expect` is wrapped in double quotes, regex is supported.
+ * 4. Break commands are collected and set globally.
+ * 5. Other commands will be send to jdb in the order they appear in the source file
+ *
+ * Note: jdb uses line number starts from 1
+ */
+
+object Gen {
+ val MainObject = "Test"
+ val CommandWait = 0.5
+
+ sealed trait Tree
+
+ case class Break(line: Int) extends Tree
+
+ case class Command(val name: String, val expect: Expect = EmptyExpect) extends Tree
+
+ sealed trait Expect
+
+ case object EmptyExpect extends Expect
+
+ case class LitExpect(lit: String) extends Expect
+
+ case class PatExpect(pat: String) extends Expect
+
+ case class Program(breaks: Seq[Break], commands: Seq[Command])
+
+ def error(msg: String): Nothing = {
+ throw new Exception(msg)
+ }
+
+ def parseCommand(command: String, lineNo: Int): Tree = {
+ val index = command.indexOf(':')
+ if (index == -1) {
+ // simple command
+ if (command == "break") Break(lineNo)
+ else Command(command)
+ } else {
+ val Seq(cmd, rhs) = command.split(":", 2).toSeq.map(_.trim)
+ if (rhs.startsWith("\"")) {
+ // regex match
+ val content = "\"(.+)\"".r
+ rhs match {
+ case content(expect) => Command(cmd, PatExpect(expect))
+ case _ => error(s"""incorrect specification: `$rhs` for `$cmd` at line $lineNo. Ending " expected.""")
+ }
+ } else {
+ // literal match
+ Command(cmd, LitExpect(rhs))
+ }
+ }
+ }
+
+ def parse(file: String): Program = {
+ val lines = Source.fromFile(file).getLines.toBuffer
+
+ val breaks = new ListBuffer[Break]()
+ val cmds = new ListBuffer[Command]()
+ lines.zipWithIndex.map { case (code, line) =>
+ val comment = if (code.indexOf("//") != -1) code.split("//").last else ""
+ val regex = """(?<=\[).*?(?=\])""".r
+ for (p <- regex findAllIn comment) parseCommand(p.trim, line + 1) match { // jdb index from 0
+ case b: Break => breaks += b
+ case c: Command => cmds += c
+ }
+ }
+
+ Program(breaks, cmds)
+ }
+
+ def generate(program: Program, source: String = "tests/debug/"): String = {
+ val Program(breaks, cmds) = program
+ val breakpoints = (breaks.map {
+ case Break(point) =>
+ s"""|send "stop at $MainObject$$:$point\\r"
+ |sleep $CommandWait
+ |expect "breakpoint $MainObject$$:$point"
+ |expect -re $$
+ """.stripMargin
+ }).mkString("\n\n")
+
+ val commands = (cmds.map {
+ case Command(cmd, EmptyExpect) =>
+ s"""|# send_user "send command `$cmd`\\n"
+ |send "$cmd\\r"
+ |sleep $CommandWait
+ |expect -re $$
+ """.stripMargin
+ case Command(cmd, LitExpect(lit)) =>
+ s"""|# send_user "send command `$cmd`\\n"
+ |send "$cmd\\r"
+ |sleep $CommandWait
+ |expect {
+ | "*$lit*" { send_user "success - $cmd : $lit \\n" }
+ | timeout {
+ | send_user "timeout while waiting for response: $cmd : $lit\\n"
+ | exit 1
+ | }
+ |}
+ |expect -re $$
+ |""".stripMargin
+ case Command(cmd, PatExpect(pat)) =>
+ s"""|# send_user "send command `$cmd`\\n"
+ |send "$cmd\\r"
+ |sleep $CommandWait
+ |expect {
+ | -re {$pat} { send_user "success - $cmd : $pat \\n" }
+ | timeout {
+ | send_user "timeout while waiting for response: $cmd : $pat\\n"
+ | exit 1
+ | }
+ |}
+ |expect -re $$
+ |""".stripMargin
+ }).mkString("\n\n")
+
+s"""|#!/usr/bin/expect
+ |
+ |# log_user 1
+ |# exp_internal 1
+ |# set timeout 5
+ |
+ |send_user "spawning job...\\n"
+ |
+ |spawn jdb -attach 5005 -sourcepath $source
+ |
+ |send_user "interacting...\\n"
+ |
+ |expect {
+ | "*VM Started*" { send_user "success - connected to server \\n" }
+ | timeout {
+ | send_user "timeout while waiting for: *VM Started*\\n"
+ | exit 1
+ | }
+ |}
+ |
+ |send_user "setting breakpoints...\\n"
+ |
+ |# breakpoints
+ |$breakpoints
+ |
+ |# run
+ |send_user "run program...\\n"
+ |send "run\\r"
+ |expect "Breakpoint hit"
+ |
+ |# interactions
+ |$commands""".stripMargin
+ }
+
+ def main(args: Array[String]): Unit = {
+ val prog = Gen.parse(args(0))
+ // println("--------------------------------")
+ // println("prog:" + prog)
+ // println("\n\n\n scrip:")
+ // println("--------------------------------")
+ println(Gen.generate(prog))
+ }
+}
diff --git a/compiler/test/debug/test b/compiler/test/debug/test
new file mode 100755
index 000000000..603e3c153
--- /dev/null
+++ b/compiler/test/debug/test
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+echo "start debug test..."
+for file in tests/debug/*.scala; do
+ ./bin/dotc $file || exit 1
+ ./bin/dotr -d Test > /dev/null &
+ $DIR/Gen $file > robot
+ expect robot 2>&1 > /dev/null
+
+ if [[ $? != 0 ]]; then
+ echo "debug test failed for file $file"
+ exit 1
+ fi
+
+ echo "$file -- success"
+done
+
+echo "debug test success!"
+
diff --git a/docs/docs/contributing/debug-tests.md b/docs/docs/contributing/debug-tests.md
new file mode 100644
index 000000000..b3d65c937
--- /dev/null
+++ b/docs/docs/contributing/debug-tests.md
@@ -0,0 +1,124 @@
+---
+layout: doc-page
+title: Tests for Debuggability
+---
+
+## Tools Requires
+
+- JDB
+- expect
+
+Both are usually pre-installed on Mac OS and linux distributions.
+
+## Debug Manually with JDB
+
+First, compile the file `tests/debug/while.scala`:
+
+```
+bin/dotc tests/debug/while.scala
+```
+
+Second, run the compiled class with debugging enabled (suppose the main class is `Test`):
+
+```
+bin/dotr -d Test
+```
+
+Third, start JDB:
+
+```
+jdb -attach 5005 -sourcepath tests/debug/
+```
+
+You can run `help` for commands that supported by JDB.
+
+## Debug Automatically with Expect
+
+### 1. Annotate the source code with debug information.
+
+Following file (`tests/debug/while.scala`) is an example of annoated source code:
+
+```Scala
+object Test {
+
+ def main(args: Array[String]): Unit = {
+ var a = 1 + 2
+ a = a + 3
+ a = 4 + 5 // [break] [step: while]
+
+ while (a * 8 < 100) { // [step: a += 1]
+ a += 1 // [step: while] [cont: print]
+ }
+
+ print(a) // [break] [cont]
+ }
+}
+```
+
+The debugging information is annotated as comments to the code in brackets:
+
+```Scala
+val x = f(3) // [break] [next: line=5]
+val y = 5
+```
+
+1. A JDB command must be wrapped in brackets, like `[step]`. All JDB commands can be used.
+2. To check output of JDB for a command, use `[cmd: expect]`.
+3. If `expect` is wrapped in double quotes, regex is supported.
+4. Break commands are collected and set globally.
+5. Other commands will be send to jdb in the order they appear in the source file
+
+Note that JDB uses line number starts from 1.
+
+### 2. Generate Expect File
+
+Now we can run the following command to generate an expect file:
+
+```
+compiler/test/debug/Gen tests/debug/while.scala > robot
+```
+
+### 3. Run the Test
+
+First, compile the file `tests/debug/while.scala`:
+
+```
+bin/dotc tests/debug/while.scala
+```
+
+Second, run the compiled class with debugging enabled:
+
+```
+bin/dotr -d Test
+```
+
+Finally, run the expect script:
+
+```
+expect robot
+```
+
+## Other Tips
+
+### Adding a New Test
+
+Just put the annotated source file under `tests/debug/`, it will be automatically
+run by the test infrastructure.
+
+### Run All Debug Tests
+
+```
+./compiler/test/debug/test
+```
+
+### Debug a Debug Test
+
+If there is any problem with a debug test, first check if the problematic
+test work correctly with JDB without automation.
+
+Then, uncomment the following line in the generated expect file to check the
+output of expect:
+
+```
+# exp_internal 1
+```
diff --git a/tests/debug/for.scala b/tests/debug/for.scala
new file mode 100644
index 000000000..b2287a988
--- /dev/null
+++ b/tests/debug/for.scala
@@ -0,0 +1,16 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ val b = 8 * 9 // [break] [step: f()]
+ f() // [step: val a]
+ 20 + b
+ print(b)
+ }
+
+ def f(): Unit = {
+ val a = for (i <- 1 to 5; j <- 10 to 20) // [cont]
+ yield (i, j) // Error: incorrect reaching this line
+
+ for (i <- 1 to 5; j <- 10 to 20)
+ println(i + j) // TODO: i is renamed to i$2 --> reduce debuggability
+ }
+} \ No newline at end of file
diff --git a/tests/debug/function.scala b/tests/debug/function.scala
new file mode 100644
index 000000000..644344414
--- /dev/null
+++ b/tests/debug/function.scala
@@ -0,0 +1,14 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ val a = 1 + 2
+ val b = a * 9 // [break] [step: plus] [step: c = plus]
+ val plus = (x: Int, y: Int) => { // [cont: x * x]
+ val a = x * x // [break] [step: y * y]
+ val b = y * y // [step: a + b]
+ a + b // [next] [next]
+ }
+ val c = plus(a, b) // [next: print]
+ print(c) // [cont]
+ }
+
+}
diff --git a/tests/debug/if.scala b/tests/debug/if.scala
new file mode 100644
index 000000000..af598c1cd
--- /dev/null
+++ b/tests/debug/if.scala
@@ -0,0 +1,20 @@
+object Test {
+
+ def main(args: Array[String]): Unit = {
+ var a = 1 + 2 // [break] [step: a + 3]
+ a = a + 3 // [step: 4 + 5]
+ a = 4 + 5 // [step: if]
+
+ if (a * 8 > 20) // [step: 9 * 9]
+ a = 9 * 9 // [step: if]
+ else
+ a = 34 * 23
+
+ if (a * 8 < 20) // [step: 34 * 23]
+ a = 9 * 9
+ else
+ a = 34 * 23 // [step: print]
+
+ print(a)
+ }
+}
diff --git a/tests/debug/method.scala b/tests/debug/method.scala
new file mode 100644
index 000000000..9489b0088
--- /dev/null
+++ b/tests/debug/method.scala
@@ -0,0 +1,14 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ val a = 1 + 2 // [break] [step: a * 9]
+ val b = a * 9 // [step: plus]
+ val c = plus(a, b) // [step: x * x]
+ print(c)
+ }
+
+ def plus(x: Int, y: Int) = {
+ val a = x * x // [step: y * y]
+ val b = y * y // [step: a + b]
+ a + b // [step: plus] [step: print] [cont]
+ }
+}
diff --git a/tests/debug/nested-method.scala b/tests/debug/nested-method.scala
new file mode 100644
index 000000000..fcc326ccb
--- /dev/null
+++ b/tests/debug/nested-method.scala
@@ -0,0 +1,15 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ val a = 1 + 2 // [break] [step: a * 9]
+ val b = a * 9 // [step: plus] [step: x * x]
+
+ def plus(x: Int, y: Int) = {
+ val a = x * x // [step: y * y]
+ val b = y * y // [step: a + b]
+ a + b // [step: plus]
+ }
+
+ val c = plus(a, b) // [step: print] [cont]
+ print(c)
+ }
+} \ No newline at end of file
diff --git a/tests/debug/sequence.scala b/tests/debug/sequence.scala
new file mode 100644
index 000000000..a6c1e9018
--- /dev/null
+++ b/tests/debug/sequence.scala
@@ -0,0 +1,11 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ var a = 1 + 2 // [break] [step: a + 3]
+ a = a + 3 // [step: 4 + 5]
+ a = 4 + 5 // [step: a * 8]
+ a = a * 8 // [step: 9 * 9]
+ a = 9 * 9 // [step: 34 * 23]
+ a = 34 * 23 // [step: print]
+ print(a) // [cont]
+ }
+} \ No newline at end of file
diff --git a/tests/debug/tailrec.scala b/tests/debug/tailrec.scala
new file mode 100644
index 000000000..f79514fa3
--- /dev/null
+++ b/tests/debug/tailrec.scala
@@ -0,0 +1,17 @@
+object Test {
+ def fact(x: Int): Int = {
+ if (x == 0)
+ 1
+ else
+ x * fact(x - 1) // TODO: incorrect this line when x = 0
+ }
+
+
+ def main(args: Array[String]): Unit = {
+ val a = 1 + 2
+ val b = a * 9 // [break] [step: fact]
+ val c = fact(a) // [step: x == 0] [step: fact(x - 1)] [step: x == 0] [cont]
+ fact(0) // [break] [step: x == 0] [step: 1] [step: fact(x - 1)] [step: print]
+ print(c) // [cont]
+ }
+} \ No newline at end of file
diff --git a/tests/debug/while.scala b/tests/debug/while.scala
new file mode 100644
index 000000000..0e5f8f8b0
--- /dev/null
+++ b/tests/debug/while.scala
@@ -0,0 +1,14 @@
+object Test {
+
+ def main(args: Array[String]): Unit = {
+ var a = 1 + 2
+ a = a + 3
+ a = 4 + 5 // [break] [step: while]
+
+ while (a * 8 < 100) { // [step: a += 1]
+ a += 1 // [step: while] [cont: print]
+ }
+
+ print(a) // [break] [cont]
+ }
+}