-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix #1484: position of while incorrect in debug
- Loading branch information
1 parent
b5a9c8c
commit 6823e15
Showing
6 changed files
with
225 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,4 +52,5 @@ build/ | |
|
||
# Put local stuff here | ||
local/ | ||
compiler/test/debug/Gen.jar | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
#!/bin/sh | ||
exec scala -savecompiled "$0" "$@" | ||
!# | ||
|
||
import scala.io.Source | ||
import scala.collection.mutable.Buffer | ||
import scala.collection.mutable.ListBuffer | ||
import scala.collection.mutable.StringBuilder | ||
|
||
/** 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 | ||
} | ||
} | ||
|
||
val prog = Gen.parse(args(0)) | ||
// println("--------------------------------") | ||
// println("prog:" + prog) | ||
// println("\n\n\n scrip:") | ||
// println("--------------------------------") | ||
println(Gen.generate(prog)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -x | ||
|
||
sbt compile package || exit 1 | ||
|
||
for file in tests/debug/*.scala; do | ||
./bin/dotc $file || exit 1 | ||
./bin/dotr -d Test& | ||
./compiler/test/debug/Gen $file > robot | ||
expect robot | ||
|
||
if [[ $? != 0 ]]; then | ||
echo "debug test failed for file $file" | ||
exit 1 | ||
fi | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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] | ||
} | ||
} |