调试支持:NLang 0.1.0 → 0.5.0
0.1.0 发出来到现在半个月,中间发了几个小版本,到最近的 0.5.0。这段时间基本只做了一件事:调试支持。
ndb 命令行调试器(0.4.0)
先是命令行的 ndb(0.4.0)。用法 ndb app.nmod,命令风格照着 gdb 抄的:
- 断点可以按
文件:行号、行号或函数名下,i b列表,d删 c继续,s/n/f三种单步,bt看调用栈,frame n切栈帧info locals、p 名字看变量,l源码窗口,x当前帧反汇编catch on在异常抛出点停住,栈和局部变量都还活着
初停行为和 gdb 的 start 一样;ndb 的退出码就是被调程序的退出码。这次字节码格式动了一版,旧的 .nmod 要重新编译。

nide IDE 集成调试(0.5.0)
然后是 0.5.0,nide 里集成了调试。按 F5 就进调试——先构建,然后跑到第一个断点;再按 F5 继续。F9 或点行号左侧的边栏下断点,F10/F11/Shift+F11 单步。
停住的时候,输出区的「调试」页能看到会话状态、调用栈和当前栈帧的局部变量,点栈帧会跳到对应行。
Shift+F5 随时终止,包括死循环和 native 调用里——这个是硬性保证,直接杀进程。

架构
顺带一提架构:nide 并不链接虚拟机,而是通过子进程跑 ndb --machine,两边用一套很小的行协议通信。
嵌入方还多了一个 IHostIo 接口,可以接管程序输出、声明没有标准输入(此时 io.readLine 会抛 IOException,而不是去读宿主的流)。
实现路线:与 gdb 的差异
实现路线上和 C 的调试器差别比较大。
gdb 那类是外部进程,不参与程序执行:靠操作系统的调试接口改写机器码下断点(x86 上就是把指令首字节换成 INT3)、用 CPU 陷阱标志做单步,变量名和行号要靠 DWARF 这类独立的调试信息段。
NLang 的做法更接近 Java 和 JavaScript 的调试器——调试支持做在虚拟机内部:
- 解释器每条语句前有一个行号检查点,断点就是在检查点上查表
- 命中后回调不返回,程序就冻在原地
- 单步也不靠 CPU 陷阱,而是记下栈深度、等下一个检查点到来
调用栈和局部变量本来就在 VM 手里(随字节码一起编译进 .nmod),不需要单独的调试信息文件。nide 和 ndb 之间的那套行协议,角色上也就相当于 JDWP 或 Chrome DevTools Protocol 的位置。
其他变化
语言本身这期间只动了一处语义:0.3.0 起 && 和 || 短路求值了(以前两边都会算)。
另外 IDE 加了「最近打开」菜单,仓库的版本号也统一由根目录一个 VERSION 文件派生。
下载
还是老样子,Windows 安装包和免安装 zip 都挂在 Releases 上:

92

被折叠的 条评论
为什么被折叠?



